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

  1. Switch to a column-list conflict target: 'on conflict (id) do update set ...' renders fine on SQL Server
  2. Ensure the column list matches the unique index you intended the named constraint to protect, so semantics are unchanged
  3. Use a native MERGE ... USING ... WHEN MATCHED THEN UPDATE WHEN NOT MATCHED THEN INSERT statement if you need exact T-SQL control
  4. 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

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


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/b192a0c1f9efeed7. Report an issue: GitHub.