hibernate/hibernate-orm · error · IllegalArgumentException
Couldn't find conflict constraint column [${constraintColumn
Error message
Couldn't find conflict constraint column [${constraintColumnName}] in insert target columns: ${targetColumnNames} What it means
When an explicit ON CONFLICT column cannot be found among the insert's target columns, buildColumnMatchPredicate throws this IllegalArgumentException (errorIfMissing=true path). The emulation needs each named conflict column to also be an inserted column so it can build the match predicate — unlike native SQL where the conflict index column need not be inserted.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/cte/CteInsertHandler.java:1317
"excluded",
columnReference.getColumnExpression(),
false,
null,
columnReference.getJdbcMapping()
),
booleanType
)
);
}
continue OUTER;
}
}
if ( errorIfMissing ) {
// Should never happen
final List<String> targetColumnNames = targetColumns.stream()
.map( ColumnReference::getColumnExpression )
.collect( Collectors.toList() );
throw new IllegalArgumentException( "Couldn't find conflict constraint column [" + constraintColumnName + "] in insert target columns: " + targetColumnNames );
}
return null;
}
return predicate;
}
private List<Assignment> getCompatibleAssignments(InsertSelectStatement dmlStatement, ConflictClause conflictClause) {
if ( conflictClause.isDoNothing() ) {
return Collections.emptyList();
}
List<Assignment> compatibleAssignments = null;
final List<Assignment> assignments = conflictClause.getAssignments();
for ( Assignment assignment : assignments ) {
for ( ColumnReference targetColumn : dmlStatement.getTargetColumns() ) {
if ( assignment.getAssignable().getColumnReferences().contains( targetColumn ) ) {
if ( compatibleAssignments == null ) {
compatibleAssignments = new ArrayList<>( assignments.size() );
}View on GitHub (pinned to fad1729dce)
Solutions
- Add the conflict column to the insert target list: `insert into Customer(id, email, name) ... on conflict (email)`
- Choose a conflict column that IS among the inserted columns
- Validate at query-build time that every conflict column is in the target list
Example fix
// before insert into Customer(id, name) select l.id, l.name from Lead l on conflict (email) // after insert into Customer(id, email, name) select l.id, l.email, l.name from Lead l on conflict (email)
Defensive patterns
Strategy: validation
Validate before calling
// Validate: every explicit conflict column must be an insert target column
Set<String> targets = new HashSet<>(targetColumns);
for (String c : conflictColumns) {
if (!targets.contains(c)) {
throw new IllegalArgumentException(
"Conflict column " + c + " must also appear in the insert target list");
}
} Try / catch
try {
em.createQuery(insertHql).executeUpdate();
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("Couldn't find conflict constraint column")) {
throw new QueryBuildException("Add the conflict column to the insert target list", e);
}
throw e;
} Prevention
- Treat ON CONFLICT columns as a subset of the insert column list in HQL (unlike native SQL)
- When renaming attributes, update both the target list and the conflict clause
- Centralize upsert HQL in reviewed constants rather than ad-hoc strings
When it happens
Trigger: `insert into Customer(id, name) select ... on conflict (email)` — email is named as the conflict column but is absent from the target column list; renaming attributes so the conflict clause references a property no longer inserted.
Common situations: Writing HQL `on conflict (col)` with PostgreSQL-native semantics in mind (where the referenced index column doesn't have to appear in the INSERT list); partial insert column lists combined with unique-key conflict handling.
Related errors
- Couldn't infer conflict constraint columns
- 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/19bb016232226659.
Report an issue: GitHub.