hibernate/hibernate-orm · error · SemanticException
Expected insert attribute count [%d] did not match Query sel
Error message
Expected insert attribute count [%d] did not match Query selection count [%d]
What it means
AbstractSqmInsertStatement.verifyInsertTypesMatch throws SemanticException when the number of insertion target paths (the attribute list in `insert into Entity (a, b)`) does not equal the number of expressions in the source SELECT list or VALUES rows. SQL INSERT requires a 1:1 mapping between target columns and source expressions; Hibernate enforces this during SQM semantic analysis, before any SQL is generated, so the mismatch fails fast at createQuery/parse time.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/insert/AbstractSqmInsertStatement.java:88
final List<SqmPath<?>> insertionTargetPaths = new ArrayList<>( this.insertionTargetPaths.size() );
for ( SqmPath<?> insertionTargetPath : this.insertionTargetPaths ) {
insertionTargetPaths.add( insertionTargetPath.copy( context ) );
}
return insertionTargetPaths;
}
}
void setConflictClause(SqmConflictClause<T> conflictClause) {
this.conflictClause = conflictClause;
}
protected void verifyInsertTypesMatch(
List<SqmPath<?>> insertionTargetPaths,
List<? extends SqmTypedNode<?>> expressions) {
final int size = insertionTargetPaths.size();
final int expressionsSize = expressions.size();
if ( size != expressionsSize ) {
throw new SemanticException(
String.format(
"Expected insert attribute count [%d] did not match Query selection count [%d]",
size,
expressionsSize
),
null,
null
);
}
for ( int i = 0; i < expressionsSize; i++ ) {
final SqmTypedNode<?> expression = expressions.get( i );
final SqmPath<?> targetPath = insertionTargetPaths.get(i);
assertAssignable( null, targetPath, expression, nodeBuilder() );
// if ( expression.getNodeJavaType() == null ) {
// continue;
// }
// if ( insertionTargetPaths.get( i ).getJavaTypeDescriptor() != expression.getNodeJavaType() ) {View on GitHub (pinned to fad1729dce)
Solutions
- Count and align: make the parenthesized attribute list and the select/values expression list the same length
- For INSERT ... VALUES, give every target attribute exactly one value expression in the same order
- For criteria inserts, check `insert.getInsertionTargetPaths().size() == source.getSelectionList().size()` before attaching the select
- If you intentionally omit columns, remove them from the target list rather than the values (or use defaults)
Example fix
// before insert into Person (id, name) select p.id, p.name, p.age from PersonBackup p // after insert into Person (id, name, age) select p.id, p.name, p.age from PersonBackup p
Defensive patterns
Strategy: validation
Validate before calling
int targets = insertionTargetPaths.size();
int sources = selectQuery.getSelectionList().size(); // or valuesRow.size()
if (targets != sources) {
throw new IllegalArgumentException("Insert needs " + targets + " expressions but select supplies " + sources);
} Try / catch
try {
session.createQuery(hql).executeUpdate();
} catch (org.hibernate.query.SemanticException e) {
// message contains both counts; align the lists and retry once at build time is a bug — fix the query
throw e;
} Prevention
- Keep target attribute list and select/values list in one place (single template or builder method)
- Add a startup/unit test that parses every static insert statement
- When adding an entity column, grep all insert-into statements for that entity
When it happens
Trigger: HQL `insert into Person (name, age) select p.name, p.age, p.salary from ...` (2 targets, 3 select items); `insert into Person (name, age) values (:n, :a, :x)` (3 values); criteria: `insert.setInsertionTargetPaths(root.get("name"), root.get("age"))` while the source query selects 3 items, or 3 target paths against a 2-column select.
Common situations: Editing a select list without updating the column list (or vice versa) during refactors; adding a column to the entity and forgetting the insert statement; generated SQL/DSL builders that render target list and select list from separate templates; copy-pasting an insert from another entity with a different attribute count.
Related errors
- The root node [" + this + "] does not allow join/fetch
- Root path treats can not be aliased - " + getNavigablePath()
- Root path treats can not be fetched - " + getNavigablePath()
- Target type '%s' is not an entity
- Cannot compare left expression of type '%s' with right expre
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/629cf445f22d0ef7.
Report an issue: GitHub.