# How Form Validation Works in Jenkins with FormValidation and Descriptor

> Understand Jenkins form validation server-side using FormValidation and Descriptor. Learn how Jelly UI fields match doCheckXyz methods for secure feedback.

- Repository: [Jenkins/jenkins](https://github.com/jenkinsci/jenkins)
- Tags: internals
- Published: 2026-07-28

---

**Jenkins performs server-side form validation by matching Jelly UI fields to `doCheckXyz` methods on a plugin's `Descriptor`, which return `FormValidation` results that core renders into safe HTML and injects back into the page.**

The `jenkinsci/jenkins` repository implements a built-in **form validation** pipeline that connects Jelly views to Java validation logic through two main abstractions: **`hudson.model.Descriptor`** and **`hudson.util.FormValidation`**. When a user types into a configured field, the frontend dispatches an AJAX request to a convention-based URL handled by the plugin descriptor, receives an HTML fragment generated by `FormValidation`, and displays it inline. This article traces the exact path from method discovery to secure response rendering.

## Descriptor Check Method Discovery

Jenkins locates validation endpoints reflectively. In [`core/src/main/java/hudson/model/Descriptor.java`](https://github.com/jenkinsci/jenkins/blob/main/core/src/main/java/hudson/model/Descriptor.java), the method **`getCheckMethod(String fieldName)`** searches the descriptor class for a `doCheckXyz` method whose suffix corresponds to the form field name. The method returns a **`FormValidation.CheckMethod`** object that constructs the URL the client-side JavaScript will later invoke. This mechanism is what links an `<f:entry>` tag in a Jelly view to a specific Java method without explicit wiring.

## Implementing `doCheckXyz` Validation Methods

Plugin authors implement validation logic by following a strict naming convention. A server-side check method must be named **`doCheckXyz`**, where `Xyz` maps to the form field, and it usually accepts **`@QueryParameter String value`** along with other annotated parameters as needed. The method must return a **`hudson.util.FormValidation`** instance.

Inside [`core/src/main/java/hudson/util/FormValidation.java`](https://github.com/jenkinsci/jenkins/blob/main/core/src/main/java/hudson/util/FormValidation.java), the class provides static factories for every severity level:

- **`FormValidation.error(String msg)`** creates an error result rendered in red.
- **`FormValidation.warning(String msg)`** creates a warning result rendered in yellow.
- **`FormValidation.ok(String msg)`** creates a success result rendered in green.

These factories ultimately call **`respond(Kind kind, String html)`**, which stores the severity and the escaped message payload.

Because `FormValidation` extends `IOException`, plugin code can also throw it as an exception to short-circuit validation and propagate the result:

```java
public FormValidation doCheckAntVersion(@QueryParameter String f) {
    try {
        return FormValidation.ok(getAntVersion(new File(f)));
    } catch (FormValidation fv) {
        return fv;
    }
}

```

For common checks, use the built-in helpers instead of writing custom logic:

```java
public class MyBuilderDescriptor extends Descriptor<MyBuilder> {

    public FormValidation doCheckTimeout(@QueryParameter String value) {
        return FormValidation.validateNonNegativeInteger(value);
    }
}

```

Executable paths can be validated with an additional custom callback:

```java
public FormValidation doCheckGitPath(@QueryParameter String git) {
    return FormValidation.validateExecutable(git, exe -> {
        return exe.getName().contains("git")
            ? FormValidation.ok()
            : FormValidation.error("Not a git executable");
    });
}

```

You can also invoke these methods directly from Java code without the UI:

```java
FormValidation fv = FormValidation.validatePositiveInteger("42");
if (fv.kind == FormValidation.Kind.OK) {
    // proceed with the valid value
}

```

This design means the same validation rule serves both interactive configuration and programmatic consumers.

## FormValidation HTML Rendering and Security

When the AJAX request is served, the `FormValidation` object handles its own response serialization. The concrete instance's rendering logic—accessed through **`generateResponse`**—wraps the message in a `<div>` element carrying the CSS class `ok`, `warning`, or `error`. All message content is escaped to prevent injection attacks.

The response is emitted with the content type `text/html;charset=UTF-8` and includes a strict Content-Security-Policy header defined in the same source file. This combination protects against XSS while allowing the browser to render the styled validation hint inline.

## Client-Side Integration with Jelly and JavaScript

The frontend wiring is handled automatically by Jenkins' Jelly form tags. Tags such as `<f:entry>` emit a `data-validation-url` attribute whose value comes from **`CheckMethod.toStemUrl()`**. The client-side JavaScript in [`war/src/main/webapp/scripts/utilities.js`](https://github.com/jenkinsci/jenkins/blob/main/war/src/main/webapp/scripts/utilities.js) listens for changes, posts the field value to that URL, and injects the returned HTML fragment directly into the DOM beside the input. This architecture gives users immediate feedback without refreshing the page.

Together, these components create a closed loop: the descriptor publishes the endpoint, the plugin author defines the rule, `FormValidation` packages a safe HTML payload, and the browser renders the result.

## Summary

- **`Descriptor.getCheckMethod`** discovers `doCheckXyz` methods reflectively and exposes a validation URL for each field.
- Plugin authors write **`doCheckXyz`** methods that accept `@QueryParameter` values and return `FormValidation` via static helpers such as `error()`, `warning()`, and `ok()`.
- **[`core/src/main/java/hudson/util/FormValidation.java`](https://github.com/jenkinsci/jenkins/blob/main/core/src/main/java/hudson/util/FormValidation.java)** constructs typed validation results and renders them as escaped HTML fragments wrapped in CSS classes.
- The HTTP response carries a strict Content-Security-Policy header to mitigate XSS risks.
- Frontend code in [`war/src/main/webapp/scripts/utilities.js`](https://github.com/jenkinsci/jenkins/blob/main/war/src/main/webapp/scripts/utilities.js) manages AJAX transport and inline display for real-time feedback.

## Frequently Asked Questions

### How does Jenkins discover which method to call for form validation?

Jenkins uses a naming convention enforced by `Descriptor.getCheckMethod(String fieldName)` in [`core/src/main/java/hudson/model/Descriptor.java`](https://github.com/jenkinsci/jenkins/blob/main/core/src/main/java/hudson/model/Descriptor.java). This method reflectively locates a plugin descriptor method named `doCheckXyz` that matches the form field name and produces a `FormValidation.CheckMethod` containing the target URL.

### What parameters can a `doCheckXyz` method accept?

The standard signature accepts **`@QueryParameter String value`**, which binds the current form input. You may add additional parameters annotated with `@QueryParameter` to supply sibling field values or context objects, and the method must always return a `FormValidation` result.

### How does `FormValidation` prevent XSS when rendering validation messages?

During response generation in [`core/src/main/java/hudson/util/FormValidation.java`](https://github.com/jenkinsci/jenkins/blob/main/core/src/main/java/hudson/util/FormValidation.java), the message is escaped before it is wrapped in a `<div>` tag. The server also serves the response with a strict Content-Security-Policy header, preventing any injected markup from executing scripts in the browser.

### Can `FormValidation` be used outside of the web UI?

Yes. Because `FormValidation` is a plain Java object that extends `IOException` and implements `HttpResponse`, backend code can invoke `doCheckXyz` methods directly. Callers simply inspect the returned object or catch it as an exception to enforce validation rules in tests, CLI commands, or background tasks.