{"record":{"id":"3a875e9c0cb4a1eb","repo":"hibernate/hibernate-orm","slug":"there-must-be-at-least-a-single-root-table-assignm","errorCode":null,"errorMessage":"There must be at least a single root table assignment","messagePattern":"There must be at least a single root table assignment","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/cte/CteInsertHandler.java","lineNumber":718,"sourceCode":"\t\t}\n\n\n\t\t// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\t\t// Add the root insert as cte\n\n\n\t\tfinal String rootTableName = entityPersister.getTableName( 0 );\n\t\tfinal TableReference rootTableReference = updatingTableGroup.getTableReference(\n\t\t\t\tupdatingTableGroup.getNavigablePath(),\n\t\t\t\trootTableName,\n\t\t\t\ttrue\n\t\t);\n\n\t\tfinal Generator identifierGenerator = entityPersister.getGenerator();\n\t\tfinal List<Map.Entry<List<CteColumn>, Assignment>> tableAssignments = assignmentsByTable.get( rootTableReference );\n\t\tif ( !assignsId && ( tableAssignments == null || tableAssignments.isEmpty() )\n\t\t\t\t&& !identifierGenerator.generatedOnExecution() ) {\n\t\t\tthrow new IllegalStateException( \"There must be at least a single root table assignment\" );\n\t\t}\n\n\t\tfinal ConflictClause conflictClause = sqmConverter.visitConflictClause( sqmStatement.getConflictClause() );\n\n\t\tfinal int tableSpan = entityPersister.getTableSpan();\n\t\tfinal List<CteColumn> keyCteColumns = queryCte.getCteTable().findCteColumns( entityPersister.getIdentifierMapping() );\n\t\tfor ( int tableIndex = 0; tableIndex < tableSpan; tableIndex++ ) {\n\t\t\tfinal String tableExpression = entityPersister.getTableName( tableIndex );\n\t\t\tfinal TableReference updatingTableReference = updatingTableGroup.getTableReference(\n\t\t\t\t\tupdatingTableGroup.getNavigablePath(),\n\t\t\t\t\ttableExpression,\n\t\t\t\t\ttrue\n\t\t\t);\n\t\t\tfinal List<Map.Entry<List<CteColumn>, Assignment>> assignmentList = assignmentsByTable.get( updatingTableReference );\n\t\t\tfinal NamedTableReference dmlTableReference = resolveUnionTableReference(\n\t\t\t\t\tupdatingTableReference,\n\t\t\t\t\ttableExpression\n\t\t\t);","sourceCodeStart":700,"sourceCodeEnd":736,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/cte/CteInsertHandler.java#L700-L736","documentation":"CteInsertHandler requires at least one assignment into the entity's ROOT table. The check fires when the statement doesn't assign the id (assignsId == false), the id generator is not generated-on-execution (i.e., manually assigned ids), AND no assignments target the root table — leaving no valid root-table INSERT to emit. It's an IllegalStateException raised during query translation.","triggerScenarios":"`insert into SubType(name) select ...` where SubType has a hand-assigned @Id (no @GeneratedValue) and every listed attribute belongs to a subclass/secondary table; omitting the id attribute from the insert target column list of an entity with assigned identifiers.","commonSituations":"HQL insert...select on entities with manually assigned or client-provided ids where the author forgot the id column; joined-inheritance inserts listing only subclass fields; legacy @Id mappings without generators being used with bulk insert statements.","solutions":["Add the id attribute to the target list: `insert into SubType(id, name)`","If ids should be database/sequence generated, configure @GeneratedValue on the id","Ensure at least one root-table attribute appears in the insert column list"],"exampleFix":"// before\ninsert into Region(code, name)\nselect c.code, c.name from Country c\n\n// after (id is manually assigned)\ninsert into Region(id, code, name)\nselect c.id, c.code, c.name from Country c","handlingStrategy":"validation","validationCode":"// Before executing insert...select, require the id (or a root column) in the target list\nEntityType<?> et = em.getMetamodel().entity(Region.class);\nif (!assignsGeneratedId(Region.class)\n        && !targetColumns.contains(et.getDeclaredId(targetIdType).getName())) {\n    throw new IllegalArgumentException(\n        \"Insert target list must include the assigned id attribute\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    em.createQuery(insertHql).executeUpdate();\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"root table assignment\")) {\n        throw new QueryBuildException(\"Add the id (or a root-table column) to the insert list\", e);\n    }\n    throw e;\n}","preventionTips":["For entities with manually assigned ids, always include the id attribute in insert...select","Use @GeneratedValue when ids should come from a sequence/identity","Codify insert target lists in one builder that validates them against the metamodel"],"tags":["hql","insert-select","cte","assigned-id","hibernate-6"],"backgroundTag":"hql-insert-select","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}