hibernate/hibernate-orm · error · IllegalStateException
Constraint paths were already set: %s
Error message
Constraint paths were already set: %s
What it means
SqmConflictClause.conflictOnConstraint(String) throws IllegalStateException when constraintPaths are already populated. Hibernate's INSERT ... ON CONFLICT support (JPA 3.2 style, exposed via HibernateCriteriaBuilder) lets you designate the conflict target either by constraint NAME or by constraint PATHS (the index columns) — never both. The object tracks which form was chosen, and switching from paths to name after paths were set is an illegal state transition on the builder.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/insert/SqmConflictClause.java:78
this.updateAction = updateAction;
}
@Nonnull
@Override
public SqmRoot<T> getExcludedRoot() {
return excludedRoot;
}
@Override
public @Nullable String getConstraintName() {
return constraintName;
}
@Nonnull
@Override
public SqmConflictClause<T> conflictOnConstraint(@Nullable String constraintName) {
if ( constraintPaths != null && !constraintPaths.isEmpty() ) {
throw new IllegalStateException( "Constraint paths were already set: " + constraintPaths );
}
this.constraintName = constraintName;
return this;
}
@Nonnull
@Override
public JpaConflictClause<T> conflictOnConstraintAttributes(String... attributes) {
final ArrayList<SqmPath<?>> paths = new ArrayList<>( attributes.length );
for ( String attribute : attributes ) {
paths.add( insertStatement.getTarget().get( attribute ) );
}
return conflictOnConstraintPaths( paths );
}
@Nonnull
@Override
public JpaConflictClause<T> conflictOnConstraintAttributes(@Nonnull SingularAttribute<T, ?>... attributes) {View on GitHub (pinned to fad1729dce)
Solutions
- Delete one of the two calls — keep either conflictOnConstraint(name) or conflictOnConstraintAttributes/Paths(columns), not both
- If you must switch dynamically, build the conflict clause once based on configuration instead of mutating the same clause object
- Before setting the name, guard with `clause.getConstraintPaths().isEmpty()`
- Check the final statement shape once in a unit test so regressions surface at build time
Example fix
// before
insert.onConflict()
.conflictOnConstraintAttributes("ssn")
.conflictOnConstraint("uk_person_ssn"); // IllegalStateException
// after
insert.onConflict()
.conflictOnConstraintAttributes("ssn"); Defensive patterns
Strategy: validation
Validate before calling
if (clause.getConstraintPaths() == null || clause.getConstraintPaths().isEmpty()) {
clause.conflictOnConstraint( constraintName );
} else {
throw new IllegalStateException("Conflict target already declared by paths");
} Prevention
- Model the conflict target as one choice (name XOR columns) in your builder config
- Never chain both conflictOnConstraint* families on the same clause
- Cover upsert statements in unit tests that render the SQL
When it happens
Trigger: Chaining `insert.onConflict().conflictOnConstraintAttributes("ssn").conflictOnConstraint("uk_person_ssn")` — first setting paths via conflictOnConstraintAttributes/Paths, then also setting a name; fluent-builder code that 'fills in' both fields unconditionally; copying both variants together while merging examples from docs.
Common situations: Migrating between the two styles during development (columns-based for dialects where the index name is unknown, name-based where it is managed by DBA) and leaving both calls in; generic query builders that set every configured option; misunderstanding that ON CONFLICT needs exactly one arbiter specification (name OR columns) in PostgreSQL-family SQL.
Related errors
- Constraint name was already set: %s
- Insert conflict 'do update' clause with constraint name is n
- Insert conflict 'do update' clause with constraint name is n
- Insert conflict 'do update' clause with constraint name is n
- Insert conflict 'do update' clause with constraint name is n
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/208b2abd6877c110.
Report an issue: GitHub.