hibernate/hibernate-orm · error · IllegalStateException
Assignment referred to columns from multiple tables
Error message
Assignment referred to columns from multiple tables
What it means
When an INSERT runs through the CTE-based multi-table strategy (joined/union inheritance or secondary tables), CteInsertHandler buckets each assignment by table. Every column of a single assignment must belong to ONE table; if the assignment's column references resolve to different table references, this IllegalStateException fires during SQM-to-SQL translation. The in-code TODO ('could be fixed by introducing joins to DML statements') marks it as a known structural limitation.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/cte/CteInsertHandler.java:687
final Map<TableReference, List<Map.Entry<List<CteColumn>, Assignment>>> assignmentsByTable = CollectionHelper.mapOfSize(
updatingTableGroup.getTableReferenceJoins().size() + 1
);
for ( int i = 0; i < assignments.size(); i++ ) {
final Map.Entry<List<CteColumn>, Assignment> entry = assignments.get( i );
final Assignment assignment = entry.getValue();
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<Map.Entry<List<CteColumn>, Assignment>> assignmentsForTable = assignmentsByTable.get( assignmentTableReference );
if ( assignmentsForTable == null ) {
assignmentsForTable = new ArrayList<>();
assignmentsByTable.put( assignmentTableReference, assignmentsForTable );
}
assignmentsForTable.add( entry );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Add the root insert as cte
View on GitHub (pinned to fad1729dce)
Solutions
- Restructure the mapping so each embedded/attribute maps to columns of a single table
- Simplify the insert target list to scalar single-table attributes
- Remove the forced CTE strategy and let Hibernate use the table-based handler
- Upgrade to the latest 6.x patch release and search Hibernate JIRA for 'Assignment referred to columns from multiple tables'; file an issue with a reproducer if the mapping is valid
Example fix
// mapping: @Embedded spanning primary + secondary table // before @Embedded Details details; // columns in both MAIN and SEC tables // after: split into two embeddables, one per table @Embedded MainDetails mainDetails; @Embedded SecondaryDetails secondaryDetails;
Defensive patterns
Strategy: try-catch
Validate before calling
// Before bulk insert on multi-table entities, assert each target attribute maps to one table
// (heuristic: avoid embeddables mixing primary- and secondary-table columns in the target list)
if (targetAttrs.stream().anyMatch(a -> a.isEmbedded())) {
log.warn("Embedded target attribute may span tables — test this insert against the CTE strategy");
} Try / catch
try {
em.createQuery(insertHql).executeUpdate();
} catch (IllegalStateException e) {
if (e.getMessage().contains("multiple tables")) {
throw new MappingIssueException(
"Assignment spans tables — split the insert or simplify the mapping: " + insertHql, e);
}
throw e;
} Prevention
- Map each embeddable/component to columns of a single table when using bulk inserts
- Test every HQL insert...select against the production mutation strategy in CI
- Watch Hibernate JIRA when using @SecondaryTable with insert...select on CTE-capable DBs
When it happens
Trigger: HQL `insert into` on an entity handled by CteInsertStrategy where one assignment is an embedded/composite or otherwise maps columns into more than one table (e.g. an @Embedded with members in both the primary and a @SecondaryTable); assignments backed by formulas spanning tables.
Common situations: Entities with @SecondaryTable whose component attributes split across tables; forcing `hibernate.query.mutation_strategy=cte` for insert...select performance and then hitting an unsupported mapping; Hibernate 6.x regressions in CTE insert handling — several JIRA issues match this invariant.
Related errors
- Assignment referred to columns from multiple tables
- There must be at least a single root table assignment
- Couldn't infer conflict constraint columns
- Assignment referred to column of a joined association: ${col
- CteInsertStrategy can only be used with Dialects that suppor
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/7c9ceeee2e978665.
Report an issue: GitHub.