hibernate/hibernate-orm · error · IllegalArgumentException
Couldn't infer conflict constraint columns
Error message
Couldn't infer conflict constraint columns
What it means
For HQL `insert ... on conflict` without explicit constraint columns, the CTE emulation falls back to the entity's primary key columns to build the row-match predicate. buildColumnMatchPredicate returns null when those key columns aren't present among the insert target columns (typical when the id is generated and omitted), and the handler aborts with this IllegalArgumentException because no conflict predicate could be inferred.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/cte/CteInsertHandler.java:1100
null,
sessionFactory
);
subquery.getSelectClause().addSqlSelection(
new SqlSelectionImpl( new QueryLiteral<>( 1, nodeBuilder.getIntegerType() ) )
);
subquery.getFromClause().addRoot( tableGroup );
List<String> columnsToMatch;
if ( constraintColumnNames.isEmpty() ) {
// Assume the primary key columns
Predicate predicate = buildColumnMatchPredicate(
columnsToMatch = Arrays.asList( ((EntityPersister) entityDescriptor).getKeyColumns( tableIndex ) ),
insertStatement,
false,
true,
booleanType
);
if ( predicate == null ) {
throw new IllegalArgumentException( "Couldn't infer conflict constraint columns" );
}
subquery.applyPredicate( predicate );
}
else {
columnsToMatch = constraintColumnNames;
subquery.applyPredicate(
buildColumnMatchPredicate( constraintColumnNames, insertStatement, true, true, booleanType ) );
}
insertQuerySpec.applyPredicate( new ExistsPredicate( subquery, true, booleanType ) );
// Emulate the conflict do update clause by creating a separate update CTEs
if ( conflictClause.isDoUpdate() ) {
final TableGroup temporaryTableGroup = insertQuerySpec.getFromClause().getRoots().get( 0 );
final QuerySpec renamingSubquery = new QuerySpec( false, 1 );
final List<String> columnNames = buildCteRenaming(
renamingSubquery,
temporaryTableGroup,View on GitHub (pinned to fad1729dce)
Solutions
- Name the conflict columns explicitly and make sure they are inserted: `on conflict (email)`
- Include the id/PK in the insert target list when you want PK-based conflict detection (e.g. insert...select that supplies ids)
- Use native SQL upsert (INSERT ... ON CONFLICT / MERGE) for dialect-specific upserts on non-native databases
Example fix
// before insert into Customer(email, name) select o.email, o.name from Lead o on conflict // after insert into Customer(email, name) select o.email, o.name from Lead o on conflict (email)
Defensive patterns
Strategy: validation
Validate before calling
// Always name conflict columns explicitly when ids are generated
if (idIsGenerated(entityClass) && conflictClauseColumns.isEmpty()) {
throw new IllegalArgumentException(
"on conflict needs explicit columns when the PK is not inserted");
} Try / catch
try {
em.createQuery(insertHql).executeUpdate();
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("infer conflict constraint")) {
throw new QueryBuildException(
"Add explicit conflict columns, e.g. 'on conflict (email)'", e);
}
throw e;
} Prevention
- Write `on conflict (col)` with explicit columns instead of bare `on conflict`
- Ensure named conflict columns appear in the insert target list
- Test upsert queries on the same database used in production — native and emulated paths differ
When it happens
Trigger: `insert into Customer(email, name) select ... on conflict` (no column list) with a @GeneratedValue id: the PK is not among targetColumns, so PK inference finds nothing to match; happens on the emulation path (dialects without native upsert, or when the CTE handler emulates the clause).
Common situations: Portable upserts written as HQL insert...select...on-conflict with generated ids — they work on PostgreSQL (native ON CONFLICT) but fail when the same query runs through emulation on other databases; adopting Hibernate 6.5+ conflict clauses without specifying an index.
Related errors
- Couldn't find conflict constraint column [${constraintColumn
- 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/05731e259cea3983.
Report an issue: GitHub.