Vì chúng đi qua hai cơ chế khác nhau.
1. @Valid trên @RequestBody — validate do argument resolver của Spring MVC thực hiện sau khi deserialize JSON. Lỗi ném MethodArgumentNotValidException (kế thừa BindException), có BindingResult chứa từng FieldError.
2. Constraint đặt thẳng trên tham số (@RequestParam @Min(1) int page) — cần @Validated ở cấp class để bật method validation qua AOP proxy. Lỗi ném ConstraintViolationException (Jakarta Bean Validation), không có BindingResult, đường dẫn lỗi ở dạng methodName.argName.
@RestController
@Validated // required for parameter-level constraints
public class ProductController {
@PostMapping("/products")
public void create(@Valid @RequestBody CreateProductRequest req) { }
@GetMapping("/products")
public List<Product> list(@RequestParam @Min(1) int page) { }
}Hậu quả thực tế: nếu @ControllerAdvice chỉ bắt MethodArgumentNotValidException thì lỗi ở query param sẽ rơi xuống handler mặc định và trả 500 thay vì 400. Phải viết handler cho cả hai loại và map về cùng một shape response.
(Từ Spring Framework 6.1 controller đã hỗ trợ built-in method validation, ném HandlerMethodValidationException khi không có @Validated — vẫn cần handler riêng.)