hibernate/hibernate-orm · error · IllegalStateException
Assignment referred to columns from multiple tables
Error message
Assignment referred to columns from multiple tables
What it means
CteUpdateHandler buckets bulk-UPDATE assignments by table exactly like the insert handler: each single assignment's column references must resolve to ONE table of the mutated entity. When an assignment (typically an embedded/composite value or a split mapping) spans columns of two tables, this IllegalStateException aborts SQL generation. The source TODO notes the limitation could only be lifted by adding joins to DML statements.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/cte/CteUpdateHandler.java:137
updatingTableGroup.getTableReferenceJoins().size() + 1
);
for ( int i = 0; i < assignments.size(); i++ ) {
final Assignment assignment = assignments.get( i );
final List<ColumnReference> assignmentColumnRefs = assignment.getAssignable().getColumnReferences();
TableReference assignmentTableReference = null;
for ( int c = 0; c < assignmentColumnRefs.size(); c++ ) {
final ColumnReference columnReference = assignmentColumnRefs.get( c );
final TableReference tableReference = resolveTableReference(
columnReference,
tableReferenceByAlias
);
// TODO: this could be fixed by introducing joins to DML statements
if ( assignmentTableReference != null && !assignmentTableReference.equals( tableReference ) ) {
throw new IllegalStateException( "Assignment referred to columns from multiple tables" );
}
assignmentTableReference = tableReference;
}
assert assignmentTableReference != null;
List<Assignment> assignmentsForTable = assignmentsByTable.get( assignmentTableReference );
if ( assignmentsForTable == null ) {
assignmentsForTable = new ArrayList<>();
assignmentsByTable.put( assignmentTableReference, assignmentsForTable );
}
assignmentsForTable.add( assignment );
}
// For nullable tables we have to also generate an insert CTE
for (int i = 0; i < entityPersister.getTableSpan(); i++) {
if ( entityPersister.isNullableTable( i ) ) {
final String tableExpression = entityPersister.getTableName( i );View on GitHub (pinned to fad1729dce)
Solutions
- Set the scalar attributes individually so each assignment lands in one table: `set p.details.a = :a, p.details.b = :b` grouped so components stay single-table
- Rework the mapping so each embedded/attribute maps to one table only
- Remove the forced CTE mutation strategy to fall back to the table-based handler
- Upgrade to the newest 6.x patch and check Hibernate JIRA; file a reproducer if the mapping is legitimate
Example fix
// before update Person p set p.details = :details // after (details split per table) update Person p set p.mainDetails = :main, p.extraDetails = :extra
Defensive patterns
Strategy: try-catch
Validate before calling
// Before bulk-updating an embeddable, confirm all its columns share one table
// (check @AttributeOverride/@Table mappings); otherwise set members individually
if (assignmentIsEmbeddable(setPath)) {
assertEmbeddableSingleTable(entityMeta, setPath);
} Try / catch
try {
em.createQuery(updateHql).executeUpdate();
} catch (IllegalStateException e) {
if (e.getMessage().contains("multiple tables")) {
throw new MappingIssueException(
"One SET assignment spans two tables — split it per table or per attribute", e);
}
throw e;
} Prevention
- Assign scalar attributes instead of whole embeddables in bulk updates
- Map embeddables so all their columns live in a single table when using bulk DML
- Exercise bulk updates on secondary-table entities in integration tests before upgrading Hibernate
When it happens
Trigger: `update Person p set p.details = :d` where the Details embeddable maps columns into both the primary table and a @SecondaryTable; SET clauses whose assignable spans formula columns across tables; bulk updates on joined-inheritance entities with cross-table components, executed via CteMutationStrategy.
Common situations: @SecondaryTable modeling where an embeddable straddles tables; switching mutation strategy to CTE on PostgreSQL and suddenly hitting this on previously-working bulk updates; Hibernate 6.x regressions around secondary-table bulk updates.
Related errors
- Assignment referred to column of a joined association: ${col
- Assignment referred to columns from multiple tables
- There must be at least a single root table assignment
- Couldn't infer conflict constraint columns
- CteMutationStrategy can only be used with Dialects that supp
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/284697fc86415638.
Report an issue: GitHub.