hibernate/hibernate-orm · error · AuditException
Changeset does not exist: <changesetId>
Error message
Changeset does not exist: <changesetId>
What it means
AuditLog.getChangesetTimestamp(changesetId) selects the changelog's timestamp property filtered by the changeset-id property; getSingleResultOrNull() returning null means no changelog row exists for the given id, so AuditException('Changeset does not exist: <id>') is thrown. The value passed does not identify any committed audit changeset.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/audit/internal/AuditLogImpl.java:350
);
}
}
// --- Changeset entity queries ---
@Override
public Instant getChangesetTimestamp(Object changesetId) {
requireNonNull( changesetId, "Changeset identifier" );
requireChangelog();
final String hql = "select e." + timestampProperty
+ " from " + changelogName + " e"
+ " where e." + changesetIdProperty + " = :rev";
final var result = auditSession
.createSelectionQuery( hql, Object.class )
.setParameter( "rev", changesetId )
.getSingleResultOrNull();
if ( result == null ) {
throw new AuditException( "Changeset does not exist: " + changesetId );
}
return toInstant( result );
}
@Override
public Object getChangesetId(Instant instant) {
requireNonNull( instant, "Instant" );
return resolveChangesetIdForTimestamp( resolveTimestampValue( instant ) );
}
@Override
public <T> T findChangeset(Class<T> changelogClass, Object changesetId) {
requireChangelog();
final var result = auditSession.createSelectionQuery(
"from " + changelogName + " where " + changesetIdProperty + " = :rev",
changelogClass
).setParameter( "rev", changesetId ).getSingleResultOrNull();
if ( result == null ) {View on GitHub (pinned to fad1729dce)
Solutions
- Obtain changeset ids only from the audit API (AuditLog.getChangesets(entityClass, id), AuditEntry.changesetId()) instead of constructing them.
- Verify the argument's runtime type equals the changelog's changeset-id property type.
- If absence is expected, look up via findChangesets(changelogClass, Set.of(id)) first - it returns a map without throwing.
Example fix
// before - entity id passed where a changeset id is expected Instant t = auditLog.getChangesetTimestamp(orderId); // after List<Object> csIds = auditLog.getChangesets(Order.class, orderId); Instant t = auditLog.getChangesetTimestamp(csIds.get(0));
Defensive patterns
Strategy: try-catch
Validate before calling
// confirm existence with the non-throwing bulk form first
Map<Object, RevEntity> found = auditLog.findChangesets(RevEntity.class, Set.of(csId));
if (found.isEmpty()) {
// handle unknown changeset without an exception
} Try / catch
try {
Instant t = auditLog.getChangesetTimestamp(csId);
}
catch (AuditException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Changeset does not exist")) {
// treat as not-found: verify the id came from getChangesets()/AuditEntry
}
else throw e;
} Prevention
- Take changeset ids only from AuditLog.getChangesets() or AuditEntry.changesetId(), never from user input
- Match the argument type to the @Changelog.ChangesetId property type
- In concurrent flows, read changesets only after the writing transaction commits
When it happens
Trigger: Passing an entity primary key instead of a changeset id, a changeset id of the wrong runtime type (long vs Long vs String), an id from another audit schema, or an id whose changeset transaction has not committed yet (the child changeset session was not flushed).
Common situations: Mixing up entity id and changeset id in API calls; type mismatch with the changelog's @Changelog.ChangesetId property type; concurrent readers querying before commit; rolled-back or deleted changesets.
Related errors
- No changeset exists at or before the given date
- 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 '<entityName>' is not audited
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/0315e263b7d9ffe9.
Report an issue: GitHub.