hibernate/hibernate-orm · error · IllegalQueryOperationException
Can't emulate conflict clause with constraint name for more
Error message
Can't emulate conflict clause with constraint name for more than one row to insert
What it means
getUniqueConstraintNameThatMayFail implements upsert on dialects (e.g., MariaDB per MariaDBSqlAstTranslator:186) by attempting the insert and catching the unique-constraint failure identified by constraint name. That emulation can only attribute a failure to a single row, so when the conflict clause carries a constraint name (and no constraint column names) but the statement inserts more than one row — a values list with >1 tuple, or an insert-select not capped to first-row-only — it throws IllegalQueryOperationException.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java:863
visitInsertStatement( sqlAst );
return new JdbcOperationQueryInsertImpl(
getSql(),
getParameterBinders(),
getAffectedTableNames(),
getUniqueConstraintNameThatMayFail(sqlAst)
);
}
protected String getUniqueConstraintNameThatMayFail(InsertSelectStatement sqlAst) {
final ConflictClause conflictClause = sqlAst.getConflictClause();
if ( conflictClause == null || !conflictClause.getConstraintColumnNames().isEmpty() ) {
return null;
}
else {
if ( sqlAst.getSourceSelectStatement() != null && !isFetchFirstRowOnly( sqlAst.getSourceSelectStatement() )
|| sqlAst.getValuesList().size() > 1 ) {
throw new IllegalQueryOperationException( "Can't emulate conflict clause with constraint name for more than one row to insert" );
}
return conflictClause.getConstraintName() == null ? "" : conflictClause.getConstraintName();
}
}
protected JdbcSelect translateSelect(SelectStatement selectStatement) {
logDomainResultGraph( selectStatement.getDomainResultDescriptors() );
logSqlAst( selectStatement );
// we need to make a cope here for later since visitSelectStatement clears it :(
final LockOptions lockOptions = this.lockOptions;
visitSelectStatement( selectStatement );
final int rowsToSkip;
final JdbcOperationQuerySelect jdbcSelect = new JdbcOperationQuerySelect(
getSql(),
getParameterBinders(),View on GitHub (pinned to fad1729dce)
Solutions
- Insert one row per statement so the emulation can attribute the constraint failure.
- Specify the conflict as constraint column names ('on conflict (col1, col2)') instead of a named constraint — the method returns null for that shape and the multi-row path proceeds.
- Omit the constraint name entirely if the single unique constraint makes it redundant.
- Execute a native MariaDB 'INSERT ... ON DUPLICATE KEY UPDATE' / 'INSERT IGNORE' statement for multi-row upserts.
Example fix
// before — multi-row insert + named constraint on MariaDB
int n = session.createQuery(
"insert into Person (id,name) values (:i1,:n1),(:i2,:n2) on conflict on constraint uk_name do nothing")
.executeUpdate();
// after — one row per statement (or conflict column names)
int n = session.createQuery(
"insert into Person (id,name) values (:i,:nm) on conflict (name) do nothing")
.setParameter("i", 1).setParameter("nm", "a").executeUpdate(); Defensive patterns
Strategy: validation
Validate before calling
boolean constraintNameUpsert = hql.contains("on conflict on constraint");
int rows = countValueTuples(hql); // rows aggregated into the insert
if (constraintNameUpsert && rows > 1) {
// MariaDB-style emulation cannot attribute multi-row failures to one constraint
throw new IllegalArgumentException("Split into single-row inserts or use conflict column names");
} Try / catch
try { session.createQuery(hql).executeUpdate(); }
catch (org.hibernate.query.IllegalQueryOperationException e) {
if (e.getMessage().contains("constraint name for more than one row")) {
splitIntoSingleRowInserts(hql).forEach(q -> q.executeUpdate());
} else { throw e; }
} Prevention
- On MariaDB, pair named-constraint upserts with single-row inserts only.
- Prefer conflict column names over named constraints for portability.
- Keep multi-row upserts in dialect-specific native SQL.
When it happens
Trigger: HQL/JPA insert with 'on conflict on constraint <name> do nothing' (empty constraint column names) plus either multiple value tuples ('values (...),(...)') or an insert-from-select whose source is not restricted to fetch first row only, executed on a dialect using the constraint-name failure emulation (MariaDB).
Common situations: Porting PostgreSQL-style upsert HQL to MariaDB; batch-insert helpers that aggregate rows into one multi-values statement; enabling the Hibernate 6.5+ HQL INSERT ... ON CONFLICT syntax on MariaDB.
Related errors
- Insert conflict clause with constraint column names is not 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/1f2a66e477684531.
Report an issue: GitHub.