{"record":{"id":"e95565dc58ead5f3","repo":"hibernate/hibernate-orm","slug":"changelog-changesetid-property-changesetidprope","errorCode":null,"errorMessage":"@Changelog.ChangesetId property '<changesetIdProperty>' is null after persisting changelog entity '<changelogClassName>'","messagePattern":"@Changelog\\.ChangesetId property '<changesetIdProperty>' is null after persisting changelog entity '<changelogClassName>'","errorType":"exception","errorClass":"AuditException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/audit/spi/ChangelogSupplier.java","lineNumber":189,"sourceCode":"\t * from the changelog entity after persistence.\n\t * <p>\n\t * Handles both regular properties and {@code @Id} properties.\n\t */\n\tprivate Object readChangesetId(\n\t\t\tObject changelog,\n\t\t\tEntityPersister persister,\n\t\t\tSharedSessionContractImplementor session) {\n\t\tfinal Object changesetId;\n\t\tfinal var changesetIdAttr = persister.findAttributeMapping( changesetIdProperty );\n\t\tif ( changesetIdAttr != null ) {\n\t\t\tchangesetId = persister.getValue( changelog, changesetIdAttr.getStateArrayPosition() );\n\t\t}\n\t\telse {\n\t\t\t// @ChangesetId is the @Id\n\t\t\tchangesetId = persister.getIdentifier( changelog, session );\n\t\t}\n\t\tif ( changesetId == null ) {\n\t\t\tthrow new AuditException(\n\t\t\t\t\t\"@Changelog.ChangesetId property '\" + changesetIdProperty\n\t\t\t\t\t+ \"' is null after persisting changelog entity '\"\n\t\t\t\t\t+ changelogClass.getName() + \"'\"\n\t\t\t);\n\t\t}\n\t\treturn changesetId;\n\t}\n\n\t/**\n\t * Persist the changelog entity using a child {@link Session}\n\t * that shares the parent session's JDBC connection.\n\t * The child session is returned so it can be kept open\n\t * for deferred flush of {@code @ElementCollection} changes.\n\t */\n\tprivate static Session persistChangelog(\n\t\t\tSharedSessionContract session,\n\t\t\tObject changelog) {\n\t\tfinal var childSession = session.sessionWithOptions()","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/audit/spi/ChangelogSupplier.java#L171-L207","documentation":"ChangelogSupplier persists the changelog entity in a child session sharing the parent's connection, flushes, then reads the @Changelog.ChangesetId property (or the @Id when the property is the id). If the value is still null - the id was neither generated nor assigned - AuditException is thrown, because the changeset id is required to stamp every audit row of that changeset.","triggerScenarios":"A changelog entity whose changeset-id property is mapped without a generator and never set before persist; an identity/trigger generator whose value is not returned on insert; a generator whose assignment happens later than the post-flush read.","commonSituations":"Hand-built changelog entities with a plain Long field and no @GeneratedValue; drivers that do not support getGeneratedKeys for the table; custom @GenericGenerator strategies that defer id assignment.","solutions":["Annotate the changeset id with @GeneratedValue (sequence/identity) so it is populated on insert, or assign it yourself before persist.","Prefer sequence-based or UUID/assigned ids so the id exists at insert time.","If using identity generation, confirm the JDBC driver returns generated keys for the changelog table."],"exampleFix":"// before - id never populated\n@Changelog.ChangesetId\nLong changesetId; // null after flush -> AuditException\n// after\n@Changelog.ChangesetId @GeneratedValue\nLong changesetId; // or set the value manually before persist","handlingStrategy":"validation","validationCode":"// with assigned ids, populate the changeset id before flush\nif (revEntity.getChangesetId() == null) {\n    revEntity.setChangesetId(nextId());\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Annotate the changeset-id property with @GeneratedValue (prefer sequences) or assign it in the constructor","Verify the driver returns generated keys when using identity columns for the changelog table","Cover changelog persistence in integration tests so id generation is exercised"],"tags":["hibernate","audit","changelog","id-generation"],"backgroundTag":"null-generated-id","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}