{"record":{"id":"e803e4c7a196143b","repo":"hibernate/hibernate-orm","slug":"null-id-generated-for-entity","errorCode":null,"errorMessage":"Null id generated for entity '","messagePattern":"Null id generated for entity '","errorType":"exception","errorClass":"IdentifierGenerationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/event/internal/AbstractSaveEventListener.java","lineNumber":109,"sourceCode":"\tprotected Object saveWithGeneratedId(\n\t\t\t@Nonnull Object entity,\n\t\t\t@Nullable String entityName,\n\t\t\t@Nonnull C context,\n\t\t\t@Nonnull EventSource source,\n\t\t\tboolean requiresImmediateIdAccess) {\n\t\tfinal var persister = source.getEntityPersister( entityName, entity );\n\t\tfinal var generator = persister.getGenerator();\n\t\tfinal boolean generatedOnExecution = generator.generatedOnExecution( entity, source );\n\t\tfinal boolean generatedBeforeExecution = generator.generatedBeforeExecution( entity, source );\n\t\tfinal Object generatedId;\n\t\tif ( generatedOnExecution ) {\n\t\t\tif ( generatedBeforeExecution\n\t\t\t\t\t&& generator instanceof CompositeNestedGeneratedValueGenerator compositeGenerator ) {\n\t\t\t\t// for a composite id, we might need to\n\t\t\t\t// create the composite id instance early\n\t\t\t\tfinal Object preGeneratedId = compositeGenerator.generate( source, entity );\n\t\t\t\tif ( preGeneratedId == null ) {\n\t\t\t\t\tthrow new IdentifierGenerationException(\n\t\t\t\t\t\t\t\"Null id generated for entity '\" + persister.getEntityName() + \"'\" );\n\t\t\t\t}\n\t\t\t\tpersister.setIdentifier( entity, preGeneratedId, source );\n\t\t\t}\n\t\t\t// the id gets generated by the database and is\n\t\t\t// not yet available\n\t\t\tgeneratedId = null;\n\t\t}\n\t\telse if ( !generator.generatesOnInsert() ) {\n\t\t\t// get it from the entity later, since we need\n\t\t\t// the @PrePersist callback to happen first\n\t\t\tgeneratedId = null;\n\t\t}\n\t\telse if ( generatedBeforeExecution ) {\n\t\t\t// go ahead and generate id, and then set it to\n\t\t\t// the entity instance, so it will be available\n\t\t\t// to the entity in the @PrePersist callback\n\t\t\tgeneratedId = generateId( entity, source, (BeforeExecutionGenerator) generator, persister );","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractSaveEventListener.java#L91-L127","documentation":"When an entity has a composite id with values generated before execution (CompositeNestedGeneratedValueGenerator, e.g. @GeneratedValue attributes inside an @EmbeddedId), AbstractSaveEventListener pre-generates the id instance during persist. If that generation returns null it throws IdentifierGenerationException('Null id generated for entity ...'): one of the nested per-attribute generators, or the mapping around it, produced no value.","triggerScenarios":"A @GeneratedValue attribute inside a composite id whose generator can return null (custom generator with an unhandled path); the manually-assigned part of the composite is null so the nested generator cannot assemble the id; generator type mismatched to the attribute type (e.g. a UUID strategy feeding a numeric field).","commonSituations":"Entities with @EmbeddedId/@IdClass containing @GeneratedValue members migrated to newer Hibernate where composite pre-generation semantics changed; custom BeforeExecutionGenerator implementations embedded in composite ids; test fixtures persisting entities without initializing the assigned part of the id.","solutions":["Review each @GeneratedValue attribute inside the composite id and replace custom generators with built-ins (sequence, uuid) or fix their null path","Set every manually-assigned attribute of the composite id before calling persist()","Write a minimal persist test for the entity to identify which id attribute generates null","If the mapping mixes assigned and generated parts awkwardly, restructure to a single generated @Id or a fully-assigned composite id"],"exampleFix":"// before: composite id with a custom generator that can return null\n@Embeddable\nclass OrderId {\n    @GeneratedValue(generator = \"myGen\")\n    Long number;\n    String tenant;\n}\n\n// after: built-in sequence for the generated part, assigned part set before persist\n@Embeddable\nclass OrderId {\n    @GeneratedValue(generator = \"order_seq\")\n    @SequenceGenerator(name = \"order_seq\", sequenceName = \"order_seq\", allocationSize = 50)\n    Long number;\n    String tenant;\n}\norder.setId(new OrderId(null, \"acme\"));","handlingStrategy":"validation","validationCode":"// before persist(): every assigned attribute of the composite id must be non-null\nOrderId id = order.getId();\nif (id == null || id.getTenant() == null) { // list all assigned parts\n    throw new IllegalStateException(\"assigned parts of the composite id must be set before persist()\");\n}\nem.persist(order);","typeGuard":"static boolean isCompositeIdComplete(OrderId id) {\n    return id != null && id.getTenant() != null; // check each assigned part\n}","tryCatchPattern":"try {\n    em.persist(order);\n} catch (IdentifierGenerationException e) {\n    // identify which @GeneratedValue attribute inside the composite id produced null\n    throw new IllegalStateException(\"composite id generation failed for \" + order.getClass().getName(), e);\n}","preventionTips":["Use built-in generators (sequence/uuid) for generated parts of composite ids","Initialize assigned parts of the id in the entity factory method","Add a persist test for every composite-id entity","Avoid mixing custom generators inside @EmbeddedId unless they are unit-tested"],"tags":["identifier-generation","composite-id","embedded-id","persist"],"backgroundTag":"identifier-generation-failed","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}