{"record":{"id":"7c9ceeee2e978665","repo":"hibernate/hibernate-orm","slug":"assignment-referred-to-columns-from-multiple-table","errorCode":null,"errorMessage":"Assignment referred to columns from multiple tables","messagePattern":"Assignment referred to columns from multiple tables","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/cte/CteInsertHandler.java","lineNumber":687,"sourceCode":"\n\t\tfinal Map<TableReference, List<Map.Entry<List<CteColumn>, Assignment>>> assignmentsByTable = CollectionHelper.mapOfSize(\n\t\t\t\tupdatingTableGroup.getTableReferenceJoins().size() + 1\n\t\t);\n\n\t\tfor ( int i = 0; i < assignments.size(); i++ ) {\n\t\t\tfinal Map.Entry<List<CteColumn>, Assignment> entry = assignments.get( i );\n\t\t\tfinal Assignment assignment = entry.getValue();\n\t\t\tfinal List<ColumnReference> assignmentColumnRefs = assignment.getAssignable().getColumnReferences();\n\n\t\t\tTableReference assignmentTableReference = null;\n\n\t\t\tfor ( int c = 0; c < assignmentColumnRefs.size(); c++ ) {\n\t\t\t\tfinal ColumnReference columnReference = assignmentColumnRefs.get( c );\n\t\t\t\tfinal TableReference tableReference = resolveTableReference( columnReference, tableReferenceByAlias );\n\n\t\t\t\t// TODO: this could be fixed by introducing joins to DML statements\n\t\t\t\tif ( assignmentTableReference != null && !assignmentTableReference.equals( tableReference ) ) {\n\t\t\t\t\tthrow new IllegalStateException( \"Assignment referred to columns from multiple tables\" );\n\t\t\t\t}\n\n\t\t\t\tassignmentTableReference = tableReference;\n\t\t\t}\n\t\t\tassert assignmentTableReference != null;\n\n\t\t\tList<Map.Entry<List<CteColumn>, Assignment>> assignmentsForTable = assignmentsByTable.get( assignmentTableReference );\n\t\t\tif ( assignmentsForTable == null ) {\n\t\t\t\tassignmentsForTable = new ArrayList<>();\n\t\t\t\tassignmentsByTable.put( assignmentTableReference, assignmentsForTable );\n\t\t\t}\n\t\t\tassignmentsForTable.add( entry );\n\t\t}\n\n\n\t\t// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\t\t// Add the root insert as cte\n","sourceCodeStart":669,"sourceCodeEnd":705,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/cte/CteInsertHandler.java#L669-L705","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// mapping: @Embedded spanning primary + secondary table\n// before\n@Embedded Details details; // columns in both MAIN and SEC tables\n\n// after: split into two embeddables, one per table\n@Embedded MainDetails mainDetails;\n@Embedded SecondaryDetails secondaryDetails;","handlingStrategy":"try-catch","validationCode":"// Before bulk insert on multi-table entities, assert each target attribute maps to one table\n// (heuristic: avoid embeddables mixing primary- and secondary-table columns in the target list)\nif (targetAttrs.stream().anyMatch(a -> a.isEmbedded())) {\n    log.warn(\"Embedded target attribute may span tables — test this insert against the CTE strategy\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    em.createQuery(insertHql).executeUpdate();\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"multiple tables\")) {\n        throw new MappingIssueException(\n            \"Assignment spans tables — split the insert or simplify the mapping: \" + insertHql, e);\n    }\n    throw e;\n}","preventionTips":["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"],"tags":["hibernate-6","cte","insert","secondary-table","inheritance","illegal-state"],"backgroundTag":"multi-table-dml-mutation","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}