hibernate/hibernate-orm · error · IllegalArgumentException
Entity '<entityName>' is not audited
Error message
Entity '<entityName>' is not audited
What it means
Every per-entity AuditLog query (getChangesets, getModificationType, find..., getHistory) first resolves the entity descriptor and requires persister.getAuditMapping() != null. For an entity without auditing there are no audit tables to read, so IllegalArgumentException('Entity ... is not audited') is thrown before any query executes.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/audit/internal/AuditLogImpl.java:447
throw new AuditException(
"No @Changelog configured. "
+ "This operation requires a changelog entity with "
+ "@Changelog.ChangesetId and @Changelog.Timestamp fields."
);
}
}
@Override
public void close() {
if ( auditSession.isOpen() ) {
auditSession.close();
}
}
private String requireAuditedEntityName(Class<?> entityClass) {
final var persister = sessionFactory.getMappingMetamodel().getEntityDescriptor( entityClass );
if ( persister.getAuditMapping() == null ) {
throw new IllegalArgumentException(
"Entity '" + persister.getEntityName() + "' is not audited"
);
}
return persister.getEntityName();
}
private static Instant toInstant(Object value) {
if ( value instanceof Instant instant ) {
return instant;
}
else if ( value instanceof LocalDateTime localDateTime ) {
return localDateTime.atZone( ZoneId.systemDefault() ).toInstant();
}
else if ( value instanceof Date date ) {
return date.toInstant();
}
else if ( value instanceof Long millis ) {
return Instant.ofEpochMilli( millis );View on GitHub (pinned to fad1729dce)
Solutions
- Annotate the entity with @Audited so audit rows are written and it becomes queryable.
- If it is intentionally unaudited, guard the call with auditLog.isAudited(entityClass) and query the live entity instead.
- For inheritance hierarchies, ensure the concrete subclass you query is audited, not just the root.
Example fix
// before
List<Object> cs = auditLog.getChangesets(UnauditedThing.class, id);
// after
if (auditLog.isAudited(UnauditedThing.class)) {
List<Object> cs = auditLog.getChangesets(UnauditedThing.class, id);
} else {
// query the live entity instead
} Defensive patterns
Strategy: validation
Validate before calling
// guard every audit call with the public check
if (auditLog.isAudited(entityClass)) {
List<Object> csIds = auditLog.getChangesets(entityClass, id);
} else {
// entity has no audit mapping: query the live table instead Type guard
static boolean isAuditedEntity(AuditLog auditLog, Class<?> entityClass) {
return auditLog.isAudited(entityClass);
} Try / catch
try {
List<Object> cs = auditLog.getChangesets(entityClass, id);
}
catch (IllegalArgumentException e) {
if (e.getMessage() != null && e.getMessage().endsWith("is not audited")) {
// audit the entity or query the live table
}
else throw e;
} Prevention
- Call auditLog.isAudited(entityClass) before generic audit queries over arbitrary classes
- Keep an explicit list of audited entity classes and validate inputs against it
When it happens
Trigger: Passing a non-audited entity class to any AuditLog find/getChangesets/getModificationType method; passing a subclass that is excluded from auditing while only its root is audited (or vice versa).
Common situations: Mixed audited/unaudited domain models where audit queries are generic; refactoring that moved classes; intentionally unaudited entities reached through shared code paths.
Related errors
- Entity '<entityName>' is not audited
- Audit graph mutation plan used with non-graph action queue
- Audit graph mutation plan used with non-graph action queue
- null key for collection: %s
- Entity change tracking is not enabled. Use a @Changelog with
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/41adf9f0f8ff572f.
Report an issue: GitHub.