hibernate/hibernate-orm · error · IllegalQueryOperationException
Insert conflict 'do update' clause with constraint name is n
Error message
Insert conflict 'do update' clause with constraint name is not supported
What it means
On SQL Server, Hibernate renders HQL INSERT ... ON CONFLICT statements as MERGE-based upserts. SQLServerSqlAstTranslator.visitConflictClause rejects the PostgreSQL-style constraint-name conflict target: when the ConflictClause is a DO UPDATE clause with getConstraintName() != null ('on conflict on constraint <name> do update'), it throws IllegalQueryOperationException at translation time, because T-SQL MERGE matches rows by join condition and cannot anchor the conflict to a named constraint.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/dialect/sql/ast/SQLServerSqlAstTranslator.java:138
}
}
@Override
protected void renderFromClauseAfterUpdateSet(UpdateStatement statement) {
if ( statement.getFromClause().getRoots().isEmpty() ) {
appendSql( " from " );
renderDmlTargetTableExpression( statement.getTargetTable() );
}
else {
visitFromClause( statement.getFromClause() );
}
}
@Override
protected void visitConflictClause(ConflictClause conflictClause) {
if ( conflictClause != null ) {
if ( conflictClause.isDoUpdate() && conflictClause.getConstraintName() != null ) {
throw new IllegalQueryOperationException( "Insert conflict 'do update' clause with constraint name is not supported" );
}
}
}
@Override
protected boolean needsRecursiveKeywordInWithClause() {
return false;
}
@Override
protected void renderTableGroupJoin(TableGroupJoin tableGroupJoin, List<TableGroupJoin> tableGroupJoinCollector) {
appendSql( WHITESPACE );
if ( tableGroupJoin.getJoinedGroup().isLateral() ) {
if ( tableGroupJoin.getJoinType() == SqlAstJoinType.LEFT ) {
appendSql( "outer apply " );
}
else {
appendSql( "cross apply " );View on GitHub (pinned to fad1729dce)
Solutions
- Switch to a column-list conflict target: 'on conflict (id) do update set ...' renders fine on SQL Server
- Ensure the column list matches the unique index you intended the named constraint to protect, so semantics are unchanged
- Use a native MERGE ... USING ... WHEN MATCHED THEN UPDATE WHEN NOT MATCHED THEN INSERT statement if you need exact T-SQL control
- Branch the HQL by dialect at runtime when one code path must serve PostgreSQL and SQL Server
Example fix
// before "insert into AuditEvent a (a.ref,a.ts) values (:r,:t) on conflict on constraint uk_auditevent_ref do update set a.ts = excluded.ts" // after "insert into AuditEvent a (a.ref,a.ts) values (:r,:t) on conflict (ref) do update set a.ts = excluded.ts"
Defensive patterns
Strategy: validation
Validate before calling
static boolean supportsConstraintNameConflictTarget(Dialect dialect) {
// SQL Server's MERGE-based rendering only matches on columns
return dialect instanceof PostgreSQLDialect;
}
String conflictClause = supportsConstraintNameConflictTarget(session.getFactory().getJdbcServices().getDialect())
? "on conflict on constraint " + name + " do update set ..."
: "on conflict (" + String.join(",", columns) + ") do update set ..."; Try / catch
try {
em.createQuery(hql).executeUpdate();
} catch (IllegalQueryOperationException e) {
if (e.getMessage().contains("constraint name is not supported")) {
em.createQuery(hqlWithColumnConflictTarget).executeUpdate();
return;
}
throw e;
} Prevention
- Use column conflict targets in all shared upsert HQL
- Test upsert queries on SQL Server in CI, not only on PostgreSQL
- Document which HQL fragments are PostgreSQL-only in the codebase
When it happens
Trigger: HQL 'insert into ... values/select ... on conflict on constraint <name> do update set ...' (or conflictOnConstraint(name) on the SQM conflict clause) executed against SQLServerDialect. Throws when the query is translated/compiled (createQuery/executeUpdate), before any JDBC round trip.
Common situations: Porting PostgreSQL upsert HQL to SQL Server; cross-dialect test suites that keep one HQL string for all backends; adopting the Hibernate 6.6+ 'on conflict' HQL clause from PostgreSQL-oriented documentation.
Related errors
- 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
- 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/b192a0c1f9efeed7.
Report an issue: GitHub.