{"record":{"id":"98cffab8f7aaa1c6","repo":"hibernate/hibernate-orm","slug":"identity-generation-requires-exactly-one-column-98cffa","errorCode":null,"errorMessage":"Identity generation requires exactly one column","messagePattern":"Identity generation requires exactly one column","errorType":"exception","errorClass":"MappingException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java","lineNumber":451,"sourceCode":"\t\t\tGeneratorSettings defaults) {\n\t\tif ( customIdGeneratorCreator != null ) {\n\t\t\tfinal var context = new IdGeneratorCreationContext( this, rootClass, property, defaults );\n\t\t\tfinal var generator = customIdGeneratorCreator.createGenerator( context );\n\t\t\tGeneratorTypeHelper.checkGeneratorGeneratedType( generator, context );\n\t\t\tif ( generator.allowAssignedIdentifiers() && nullValue == null ) {\n\t\t\t\tsetNullValueUndefined();\n\t\t\t}\n\t\t\treturn generator;\n\t\t}\n\t\telse {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t@Internal\n\tpublic void setColumnToIdentity() {\n\t\tif ( getColumnSpan() != 1 ) {\n\t\t\tthrow new MappingException( \"Identity generation requires exactly one column\" );\n\t\t}\n\t\telse if ( getColumn(0) instanceof Column column ) {\n\t\t\tcolumn.setIdentity( true );\n\t\t}\n\t\telse {\n\t\t\tthrow new MappingException( \"Identity generation requires a column\" );\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean isUpdateable() {\n\t\t//needed to satisfy KeyValue\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic FetchStyle getFetchStyle() {\n\t\treturn FetchStyle.SELECT;","sourceCodeStart":433,"sourceCodeEnd":469,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java#L433-L469","documentation":"setColumnToIdentity() requires the value to map exactly one real column. Identity-based generation (auto-increment) works only on a single column, so a value spanning zero or multiple columns (composite ids, formula-only ids) is rejected. It usually surfaces while binding @GeneratedValue(strategy = IDENTITY).","triggerScenarios":"@GeneratedValue(strategy = GenerationType.IDENTITY) on an @EmbeddedId or composite key spanning multiple columns; an id mapping built from a formula instead of a column; an hbm identity generator class on a multi-column id.","commonSituations":"Switching an entity from a simple to a composite id while keeping IDENTITY; database-first generated mappings; copy-pasting generator settings between simple and composite ids.","solutions":["Use a single-column id with IDENTITY generation","For composite ids, use assigned identifiers or a surrogate key with a table/sequence generator","If the id was meant to be simple, remove the extra key columns or formulas"],"exampleFix":"// before\n@EmbeddedId\n@GeneratedValue(strategy = GenerationType.IDENTITY)\nprivate OrderId id; // OrderId spans 2 columns\n\n// after\n@Id\n@GeneratedValue(strategy = GenerationType.IDENTITY)\nprivate Long id;","handlingStrategy":"validation","validationCode":"if (pc instanceof RootClass root) {\n    Value id = root.getIdentifier();\n    boolean singleRealColumn = id.getColumnSpan() == 1\n            && id.getColumns().get(0) instanceof Column;\n    if (!singleRealColumn && usesIdentityGeneration(root)) {\n        // IDENTITY cannot be used; switch the generator strategy before binding\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use IDENTITY generation only with a single-column surrogate id","For composite keys, prefer assigned ids or a table/sequence-generated surrogate","Re-check generator strategy whenever an id changes shape"],"tags":["hibernate","orm","identity-generation","composite-key","mapping"],"backgroundTag":"id-generation-misconfigured","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}