Introduction
When JPA auto-validates entities before persisting or updating, any violated Bean Validation constraint throws ConstraintViolationException. This happens at flush/commit time, not when the entity is created, making it harder to trace back to the root cause.
This error is common when entities have @NotNull, @Size, @Pattern, or custom validation constraints that are not satisfied by the incoming data.
Symptoms
- Application throws "javax.validation.ConstraintViolationException" during entity persist or merge
- Error shows which constraint failed: "must not be null", "size must be between 1 and 100"
- Validation happens at transaction commit, not when setting the entity field
Common Causes
- Required field (@NotNull) is null when the entity is persisted
- String length exceeds @Size or @Pattern constraint limits
- Custom validator logic rejects the entity state
Step-by-Step Fix
- 1.Identify the violated constraint from the exception: The exception contains details about what failed.
- 2.```java
- 3.try {
- 4.entityManager.persist(user);
- 5.entityManager.flush();
- 6.} catch (ConstraintViolationException e) {
- 7.for (ConstraintViolation<?> violation : e.getConstraintViolations()) {
- 8.System.err.printf("Field: %s, Value: %s, Message: %s%n",
- 9.violation.getPropertyPath(),
- 10.violation.getInvalidValue(),
- 11.violation.getMessage());
- 12.}
- 13.// Example output:
- 14.// Field: email, Value: null, Message: must not be null
- 15.// Field: username, Value: "ab", Message: size must be between 3 and 50
- 16.}
- 17.
` - 18.Validate before persisting using the Validator API: Catch validation errors early.
- 19.```java
- 20.import javax.validation.Validator;
@Autowired private Validator validator;
public User createUser(User user) { Set<ConstraintViolation<User>> violations = validator.validate(user); if (!violations.isEmpty()) { throw new IllegalArgumentException( violations.stream() .map(ConstraintViolation::getMessage) .collect(Collectors.joining(", ")) ); } return userRepository.save(user); } ```
- 1.Use validation groups for partial validation: Apply different constraints for create vs update.
- 2.```java
- 3.public interface OnCreate {}
- 4.public interface OnUpdate {}
public class User { @NotNull(groups = OnCreate.class) @Null(groups = OnUpdate.class) private Long id;
@NotBlank(groups = {OnCreate.class, OnUpdate.class}) private String email;
@Size(min = 3, max = 50, groups = OnCreate.class) private String username; }
// Validate with specific group: validator.validate(user, OnCreate.class); ```
Prevention
- Validate entities at the service layer boundary, not at the persistence layer
- Use Bean Validation in your REST controllers with @Valid on request bodies
- Log validation violations with full property path and value for easier debugging
- Use validation groups to differentiate between create, update, and partial update scenarios