{"record":{"id":"6f6029f1980e52bb","repo":"hibernate/hibernate-orm","slug":"changelog-must-have-a-property-annotated-wit-6f6029","errorCode":null,"errorMessage":"@Changelog '{}' must have a property annotated with @Changelog.Timestamp","messagePattern":"@Changelog '(.+?)' must have a property annotated with @Changelog\\.Timestamp","errorType":"exception","errorClass":"MappingException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/boot/model/internal/AuditHelper.java","lineNumber":470,"sourceCode":"\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;\n\t\tfinal var supplier = new ChangelogSupplier<>(\n\t\t\t\tclassDetails.toJavaClass(),\n\t\t\t\trevNumberMember.resolveAttributeName(),\n\t\t\t\trevTimestampMember.resolveAttributeName(),\n\t\t\t\tmodifiedEntityNamesMember != null\n\t\t\t\t\t\t? modifiedEntityNamesMember.resolveAttributeName()","sourceCodeStart":452,"sourceCodeEnd":488,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AuditHelper.java#L452-L488","documentation":"An '@Changelog' entity must contain a member annotated '@Changelog.Timestamp' so each changeset can be stamped with a time. AuditHelper's eager scan of the class (and supertypes) found the changeset-id member but no @Changelog.Timestamp field, so it throws during metadata building — the timestamp is required to configure the changeset supplier before audit second passes run.","triggerScenarios":"An '@Changelog @Entity' with a @Changelog.ChangesetId field but no field annotated '@Changelog.Timestamp'; the timestamp annotation on a getter rather than a scanned field; a copy of the changeset entity from which the timestamp member was deleted.","commonSituations":"Following a partial example of the new Hibernate audit API; refactoring that removed the 'at' field; assuming the revision timestamp is optional like in Envers @RevisionEntity.","solutions":["Add a field annotated '@Changelog.Timestamp' (e.g. 'Instant at') to the changelog entity.","Keep the annotation on the FIELD, in the entity or one of its mapped supertypes, spelled exactly '@Changelog.Timestamp'.","Keep '@Changelog.ChangesetId' present too — both members are mandatory and validated in order."],"exampleFix":"// before\n@Changelog\n@Entity\npublic class Changeset {\n    @Id @GeneratedValue\n    @Changelog.ChangesetId\n    Long id;\n    // no timestamp member -> error\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.Timestamp field\nboolean hasTs = Arrays.stream(cls.getDeclaredFields())\n    .anyMatch(f -> f.isAnnotationPresent(Changelog.Timestamp.class));\nif (cls.isAnnotationPresent(Changelog.class) && !hasTs) {\n    throw new IllegalStateException(cls.getName()\n        + \": missing @Changelog.Timestamp member\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    factory = cfg.buildSessionFactory();\n} catch (MappingException e) {\n    // 'must have a property annotated with @Changelog.Timestamp' -> add it\n    throw newConfigurationException(\"Incomplete changelog entity\", e);\n}","preventionTips":["Both @Changelog.ChangesetId and @Changelog.Timestamp are mandatory; add them together.","Use field access (not getters) for changelog marker annotations, matching the binder's field scan."],"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"}