Skip to content
Spring Boot sb validation 3 min read

Validating Path & Query Params

Request bodies aren’t the only untrusted input — query parameters and path variables need validation too. These are simple scalars rather than objects, so they’re validated differently: you put constraints directly on the parameters and opt the controller into method-level validation with Spring’s @Validated. This page also covers validating @ConfigurationProperties.

@Validated on the controller class

Method-parameter validation is off by default. Enable it by annotating the class with Spring’s @Validated (from org.springframework.validation.annotation). Then put constraint annotations directly on the @RequestParam / @PathVariable arguments.

import jakarta.validation.constraints.*;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/products")
@Validated                                   // enables param-level validation
public class ProductController {

    @GetMapping
    public List<Product> list(
            @RequestParam @Min(0) int page,
            @RequestParam @Min(1) @Max(100) int size,
            @RequestParam(required = false) @Size(max = 50) String search) {
        return service.find(page, size, search);
    }

    @GetMapping("/{id}")
    public Product one(@PathVariable @Positive Long id) {
        return service.findById(id);
    }
}

Warning: Without @Validated on the class, the constraints on @RequestParam/@PathVariable are silently ignored. This is the single most common reason param validation “doesn’t work.” The annotation must be on the class (or a @Configuration-registered bean), not the method.

ConstraintViolationException

When a parameter constraint fails, Spring throws ConstraintViolationException (from jakarta.validation) — a different exception than the MethodArgumentNotValidException used for request bodies.

curl "http://localhost:8080/api/products?page=-1&size=999"

By default this surfaces as 500 Internal Server Error, which is wrong — bad client input should be a 400. Map it explicitly in a @RestControllerAdvice:

import jakarta.validation.ConstraintViolationException;

@RestControllerAdvice
public class ParamValidationHandler {

    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Map<String, String> onConstraintViolation(ConstraintViolationException ex) {
        Map<String, String> errors = new HashMap<>();
        ex.getConstraintViolations().forEach(v -> {
            String field = v.getPropertyPath().toString();   // e.g. "list.size"
            errors.put(field, v.getMessage());
        });
        return errors;
    }
}

Output:

{
  "list.page": "must be greater than or equal to 0",
  "list.size": "must be less than or equal to 100"
}

Note the property path includes the method name (list.size) rather than a clean field name. Trim it if you want friendlier output. The full handling strategy lives in Handling Validation Errors.

Body vs param validation — at a glance

Aspect@RequestBody@RequestParam / @PathVariable
Trigger annotation@Valid on the parameter@Validated on the class
Where constraints goon DTO fieldsdirectly on the method parameter
Exception on failureMethodArgumentNotValidExceptionConstraintViolationException
Default status400500 (until you map it)
Error detailBindingResult / FieldErrorSet<ConstraintViolation>

Validating @ConfigurationProperties

Validation isn’t limited to web requests. You can validate externalized configuration at startup so the application fails fast on a bad application.yml. Annotate the properties class with @Validated and add constraints to its fields.

import jakarta.validation.constraints.*;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;

@ConfigurationProperties(prefix = "app.mail")
@Validated
public record MailProperties(
        @NotBlank String host,
        @Min(1) @Max(65535) int port,
        @Email String fromAddress) {}
app:
  mail:
    host: smtp.example.com
    port: 587
    fromAddress: [email protected]

If a value is missing or invalid, the application context fails to start with a clear message:

***************************
APPLICATION FAILED TO START
***************************

Binding to target ... failed:

    Property: app.mail.port
    Value: "70000"
    Reason: must be less than or equal to 65535

Tip: Failing fast at startup is far safer than discovering a misconfiguration at runtime. Pair validated @ConfigurationProperties with profiles to enforce per-environment configuration contracts. See also Type-safe Configuration Properties.

Validating @RequestHeader and other params

The same rules apply to any method parameter resolved by Spring MVC. With @Validated on the class you can constrain @RequestHeader, @CookieValue, and @MatrixVariable:

@GetMapping("/feed")
public Feed feed(@RequestHeader("X-Api-Version") @Pattern(regexp = "v[12]") String version) {
    return service.feed(version);
}
Last updated June 13, 2026
Was this helpful?