{"record":{"id":"8963e17de79248ea","repo":"hibernate/hibernate-orm","slug":"entity-change-tracking-is-not-enabled-use-a-chan","errorCode":null,"errorMessage":"Entity change tracking is not enabled. Use a @Changelog with a @Changelog.ModifiedEntities property (e.g. DefaultTrackingModifiedEntitiesChangelog).","messagePattern":"Entity change tracking is not enabled\\. Use a @Changelog with a @Changelog\\.ModifiedEntities property \\(e\\.g\\. DefaultTrackingModifiedEntitiesChangelog\\)\\.","errorType":"exception","errorClass":"AuditException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/audit/internal/AuditLogImpl.java","lineNumber":328,"sourceCode":"\t\tfor ( String entityName : queryRevChangesEntityNames( changesetId ) ) {\n\t\t\tdoFindEntitiesGroupedByModificationType( entityName, changesetId, Object.class )\n\t\t\t\t\t.forEach( (mt, entities) -> result.get( mt ).addAll( entities ) );\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate List<String> queryRevChangesEntityNames(Object changesetId) {\n\t\treturn auditSession.createSelectionQuery(\n\t\t\t\t\"select element(r.\" + modifiedEntitiesProperty + \")\"\n\t\t\t\t\t\t+ \" from \" + changelogName + \" r\"\n\t\t\t\t\t\t+ \" where r.\" + changesetIdProperty + \" = :csId\",\n\t\t\t\tString.class\n\t\t).setParameter( \"csId\", changesetId ).getResultList();\n\t}\n\n\tprivate void requireEntityChangeTracking() {\n\t\tif ( modifiedEntitiesProperty == null ) {\n\t\t\tthrow new AuditException(\n\t\t\t\t\t\"Entity change tracking is not enabled. \"\n\t\t\t\t\t\t\t+ \"Use a @Changelog with a @Changelog.ModifiedEntities property \"\n\t\t\t\t\t\t\t+ \"(e.g. DefaultTrackingModifiedEntitiesChangelog).\"\n\t\t\t);\n\t\t}\n\t}\n\n\t// --- Changeset entity queries ---\n\n\t@Override\n\tpublic Instant getChangesetTimestamp(Object changesetId) {\n\t\trequireNonNull( changesetId, \"Changeset identifier\" );\n\t\trequireChangelog();\n\t\tfinal String hql = \"select e.\" + timestampProperty\n\t\t\t\t+ \" from \" + changelogName + \" e\"\n\t\t\t\t+ \" where e.\" + changesetIdProperty + \" = :rev\";\n\t\tfinal var result = auditSession\n\t\t\t\t.createSelectionQuery( hql, Object.class )","sourceCodeStart":310,"sourceCodeEnd":346,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/audit/internal/AuditLogImpl.java#L310-L346","documentation":"Cross-changeset queries on AuditLog - getEntityTypesModifiedAt, findAllEntitiesModifiedAt, findAllEntitiesGroupedByModificationType - read the list of changed entity names from the @Changelog.ModifiedEntities property of the changelog entity. When the configured changelog has no such property, requireEntityChangeTracking() throws AuditException explaining how to enable tracking.","triggerScenarios":"Calling any AuditLog.findAllEntitiesModifiedAt / getEntityTypesModifiedAt / findAllEntitiesGroupedByModificationType variant while the registered changelog entity only has changeset-id and timestamp properties.","commonSituations":"Starting with a minimal changelog for at-changeset queries, then later calling modified-entity queries; porting Envers getCrossTypeRevisionChangesReader code that required ModifiedEntityNamesConfig.","solutions":["Extend DefaultTrackingModifiedEntitiesChangelog, or add a @Changelog.ModifiedEntities property to your changelog entity, then update the schema.","If entity-change tracking is not needed, replace these calls with per-entity queries (getChangesets / find at changeset) that do not require the property."],"exampleFix":"// before\n@Changelog\npublic class RevEntity {\n    @Changelog.ChangesetId @GeneratedValue Long id;\n    @Changelog.Timestamp Instant at;\n}\n// after - changelog that tracks modified entity names\n@Changelog\npublic class RevEntity extends DefaultTrackingModifiedEntitiesChangelog { ... }","handlingStrategy":"validation","validationCode":"// feature check before calling modified-entity APIs\nboolean trackingEnabled = /* changelog entity declares a @Changelog.ModifiedEntities property */\n    Arrays.stream(RevEntity.class.getDeclaredFields())\n        .anyMatch(f -> f.isAnnotationPresent(Changelog.ModifiedEntities.class));\nif (!trackingEnabled) throw new UnsupportedOperationException(\"enable modified-entity tracking first\");","typeGuard":null,"tryCatchPattern":"try {\n    types = auditLog.getEntityTypesModifiedAt(csId);\n}\ncatch (AuditException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Entity change tracking is not enabled\")) {\n        // fall back to per-entity queries that need no changelog tracking\n    }\n    else throw e;\n}","preventionTips":["Start from DefaultTrackingModifiedEntitiesChangelog so tracking is present from day one","Document which AuditLog methods require changelog features before teammates call them"],"tags":["hibernate","audit","changelog","configuration"],"backgroundTag":"audit-tracking-not-enabled","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}