{"record":{"id":"c92805d46517624a","repo":"hibernate/hibernate-orm","slug":"changelog-must-have-a-property-annotated-wit","errorCode":null,"errorMessage":"@Changelog '{}' must have a property annotated with @Changelog.ChangesetId","messagePattern":"@Changelog '(.+?)' must have a property annotated with @Changelog\\.ChangesetId","errorType":"exception","errorClass":"MappingException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/boot/model/internal/AuditHelper.java","lineNumber":464,"sourceCode":"\t\t\t\t\t\tclassDetails\n\t\t\t\t);\n\t\t\t\trevTimestampMember = checkAnnotation(\n\t\t\t\t\t\tmember,\n\t\t\t\t\t\trevTimestampMember,\n\t\t\t\t\t\tChangelog.Timestamp.class,\n\t\t\t\t\t\tclassDetails\n\t\t\t\t);\n\t\t\t\tmodifiedEntityNamesMember = checkAnnotation(\n\t\t\t\t\t\tmember,\n\t\t\t\t\t\tmodifiedEntityNamesMember,\n\t\t\t\t\t\tChangelog.ModifiedEntities.class,\n\t\t\t\t\t\tclassDetails\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif ( revNumberMember == null ) {\n\t\t\tthrow new MappingException(\n\t\t\t\t\t\"@Changelog '\" + classDetails.getName()\n\t\t\t\t\t\t\t+ \"' must have a property annotated with @Changelog.ChangesetId\"\n\t\t\t);\n\t\t}\n\t\tif ( revTimestampMember == null ) {\n\t\t\tthrow new MappingException(\n\t\t\t\t\t\"@Changelog '\" + classDetails.getName()\n\t\t\t\t\t\t\t+ \"' must have a property annotated with @Changelog.Timestamp\"\n\t\t\t);\n\t\t}\n\n\t\t// Configure the supplier eagerly\n\t\tfinal var serviceRegistry = context.getBootstrapContext().getServiceRegistry();\n\t\tfinal var listenerClass = changelog.listener();\n\t\tfinal var listener = listenerClass != ChangesetListener.class\n\t\t\t\t? serviceRegistry.requireService( ManagedBeanRegistry.class )\n\t\t\t\t\t\t.getBean( listenerClass ).getBeanInstance()\n\t\t\t\t: null;","sourceCodeStart":446,"sourceCodeEnd":482,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AuditHelper.java#L446-L482","documentation":"A changelog (changeset) entity declared with Hibernate 7's '@Changelog' must contain exactly one member annotated '@Changelog.ChangesetId' to identify each changeset. AuditHelper scans the class and its supertypes for that marker; if no field carries it, binding throws this MappingException during metadata building.","triggerScenarios":"An '@Changelog @Entity' class with @Changelog.Timestamp and/or @Changelog.ModifiedEntities fields but NO field annotated '@Changelog.ChangesetId'; annotating a method instead of a field; misspelling the nested annotation so the scan misses it.","commonSituations":"Building the changeset entity from the docs and skipping the id member; renaming/refactoring that dropped the annotation; hand-porting an Envers @RevisionEntity where the id used @Id + @GeneratedValue instead of the changelog marker.","solutions":["Add a field annotated '@Changelog.ChangesetId' to the @Changelog entity — typically the primary key of each changeset row (e.g. Long id with a generator).","Make sure the annotation is the exact nested type '@Changelog.ChangesetId' on a FIELD of the entity or one of its mapped supertypes.","Ensure exactly one such member: also add the required '@Changelog.Timestamp' member (checked next)."],"exampleFix":"// before\n@Changelog\n@Entity\npublic class Changeset {\n    @Id @GeneratedValue Long id; // not a @ChangesetId\n    @Changelog.Timestamp Instant at;\n}\n\n// after\n@Changelog\n@Entity\npublic class Changeset {\n    @Id @GeneratedValue\n    @Changelog.ChangesetId\n    Long id;\n\n    @Changelog.Timestamp\n    Instant at;\n}","handlingStrategy":"validation","validationCode":"// Guard: @Changelog entity must have a @Changelog.ChangesetId field\nboolean hasId = Arrays.stream(cls.getDeclaredFields())\n    .anyMatch(f -> f.isAnnotationPresent(Changelog.ChangesetId.class));\nif (cls.isAnnotationPresent(Changelog.class) && !hasId) {\n    throw new IllegalStateException(cls.getName()\n        + \": missing @Changelog.ChangesetId member\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    factory = cfg.buildSessionFactory();\n} catch (MappingException e) {\n    // 'must have a property annotated with @Changelog.ChangesetId' -> add it\n    throw newConfigurationException(\"Incomplete changelog entity\", e);\n}","preventionTips":["Start changelog entities from a reviewed template containing ChangesetId + Timestamp members.","Write one bootstrap test that instantiates the audit configuration; it catches all three @Changelog errors."],"tags":["hibernate","changelog","auditing","orm-mapping"],"backgroundTag":"audit-mapping-error","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}