hibernate/hibernate-orm · error · MappingException

@Changelog '{}' must have a property annotated with @Changel

Error message

@Changelog '{}' must have a property annotated with @Changelog.Timestamp

What it means

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.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/internal/AuditHelper.java:470

						classDetails
				);
				modifiedEntityNamesMember = checkAnnotation(
						member,
						modifiedEntityNamesMember,
						Changelog.ModifiedEntities.class,
						classDetails
				);
			}
		}

		if ( revNumberMember == null ) {
			throw new MappingException(
					"@Changelog '" + classDetails.getName()
							+ "' must have a property annotated with @Changelog.ChangesetId"
			);
		}
		if ( revTimestampMember == null ) {
			throw new MappingException(
					"@Changelog '" + classDetails.getName()
							+ "' must have a property annotated with @Changelog.Timestamp"
			);
		}

		// Configure the supplier eagerly
		final var serviceRegistry = context.getBootstrapContext().getServiceRegistry();
		final var listenerClass = changelog.listener();
		final var listener = listenerClass != ChangesetListener.class
				? serviceRegistry.requireService( ManagedBeanRegistry.class )
						.getBean( listenerClass ).getBeanInstance()
				: null;
		final var supplier = new ChangelogSupplier<>(
				classDetails.toJavaClass(),
				revNumberMember.resolveAttributeName(),
				revTimestampMember.resolveAttributeName(),
				modifiedEntityNamesMember != null
						? modifiedEntityNamesMember.resolveAttributeName()

View on GitHub (pinned to fad1729dce)

Solutions

  1. Add a field annotated '@Changelog.Timestamp' (e.g. 'Instant at') to the changelog entity.
  2. Keep the annotation on the FIELD, in the entity or one of its mapped supertypes, spelled exactly '@Changelog.Timestamp'.
  3. Keep '@Changelog.ChangesetId' present too — both members are mandatory and validated in order.

Example fix

// before
@Changelog
@Entity
public class Changeset {
    @Id @GeneratedValue
    @Changelog.ChangesetId
    Long id;
    // no timestamp member -> error
}

// after
@Changelog
@Entity
public class Changeset {
    @Id @GeneratedValue
    @Changelog.ChangesetId
    Long id;

    @Changelog.Timestamp
    Instant at;
}
Defensive patterns

Strategy: validation

Validate before calling

// Guard: @Changelog entity must have a @Changelog.Timestamp field
boolean hasTs = Arrays.stream(cls.getDeclaredFields())
    .anyMatch(f -> f.isAnnotationPresent(Changelog.Timestamp.class));
if (cls.isAnnotationPresent(Changelog.class) && !hasTs) {
    throw new IllegalStateException(cls.getName()
        + ": missing @Changelog.Timestamp member");
}

Try / catch

try {
    factory = cfg.buildSessionFactory();
} catch (MappingException e) {
    // 'must have a property annotated with @Changelog.Timestamp' -> add it
    throw newConfigurationException("Incomplete changelog entity", e);
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/6f6029f1980e52bb. Report an issue: GitHub.