hibernate/hibernate-orm · error · HibernateException

Setting 'hibernate.temporal.changeset_id_supplier' must spec

Error message

Setting 'hibernate.temporal.changeset_id_supplier' must specify a 'org.hibernate.temporal.spi.ChangesetIdentifierSupplier' implementation

What it means

hibernate.temporal.changeset_id_supplier accepts an instance, a Class, or a class-name String. When the value is a Class that is not assignable to org.hibernate.temporal.spi.ChangesetIdentifierSupplier, strategy resolution is refused with this HibernateException — a temporal supplier must implement that SPI interface, and Hibernate will not coerce or adapt other generator types.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/temporal/internal/ChangesetCoordinatorImpl.java:124

			// session across calls to the database
			&& dialect.isCurrentTimestampStable();
	}

	private ChangesetIdentifierSupplier<?> resolveSupplier(
			Map<String,Object> settings,
			StrategySelector strategySelector) {
		final Object setting = settings.get( CHANGESET_ID_SUPPLIER );
		if ( setting == null ) {
			return this;
		}
		else if ( setting instanceof ChangesetIdentifierSupplier<?> supplier ) {
			return supplier;
		}
		else if ( setting instanceof Class<?> clazz ) {
			if ( ChangesetIdentifierSupplier.class.isAssignableFrom( clazz ) ) {
				return strategySelector.resolveStrategy( ChangesetIdentifierSupplier.class, clazz );
			}
			throw new HibernateException(
					"Setting '" + CHANGESET_ID_SUPPLIER + "' must specify a '"
					+ ChangesetIdentifierSupplier.class.getName()
					+ "' implementation"
			);
		}
		else if ( setting instanceof String name ) {
			return strategySelector.resolveStrategy( ChangesetIdentifierSupplier.class, name );
		}
		else {
			throw new HibernateException(
					"Setting '" + CHANGESET_ID_SUPPLIER + "' must specify a '"
					+ ChangesetIdentifierSupplier.class.getName()
					+ "' instance, class, or class name"
			);
		}
	}

	private static Class<?> resolveSuppliedType(Class<? extends ChangesetIdentifierSupplier<?>> supplierClass) {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Make the configured class implement org.hibernate.temporal.spi.ChangesetIdentifierSupplier, with a public no-arg constructor so strategy resolution can build it.
  2. Alternatively pass an already-constructed instance or the fully-qualified class-name string of a correct implementation.

Example fix

// before
public class UuidChangesetIdSupplier { ... } // does not implement the SPI

// after
public class UuidChangesetIdSupplier
        implements org.hibernate.temporal.spi.ChangesetIdentifierSupplier<UUID> {
    public UuidChangesetIdSupplier() {}
    ...
}
Defensive patterns

Strategy: type-guard

Validate before calling

Object v = settings.get("hibernate.temporal.changeset_id_supplier");
if (v instanceof Class<?> clazz
        && !org.hibernate.temporal.spi.ChangesetIdentifierSupplier.class.isAssignableFrom(clazz)) {
    throw new IllegalStateException(clazz + " does not implement ChangesetIdentifierSupplier");
}

Type guard

static boolean isChangesetSupplier(Class<?> clazz) {
    return org.hibernate.temporal.spi.ChangesetIdentifierSupplier.class.isAssignableFrom(clazz);
}

Prevention

When it happens

Trigger: Putting a Class object under the setting that implements some other generator interface (a generic IdentifierGenerator, a supplier for a different feature) or a class that lost its implements clause during refactoring: the ChangesetIdentifierSupplier.class.isAssignableFrom(clazz) check fails and the exception is thrown.

Common situations: Adapting an existing id-generator class to temporal versioning without implementing the SPI; refactoring the supplier into a new class that no longer implements the interface; passing the class of a supplier compiled against an incompatible version.

Related errors


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