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' instance, class, or class name

What it means

The changeset-id-supplier setting handles exactly three value shapes: a ChangesetIdentifierSupplier instance, a Class object, or a String class name. Any other runtime type falls through to the final else-branch and bootstrap fails with this HibernateException naming the accepted shapes.

Source

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

		}
		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) {
		final var supplierInstantiation = supertypeInstantiation( ChangesetIdentifierSupplier.class, supplierClass );
		if ( supplierInstantiation == null ) {
			return null;
		}
		else {
			final var typeArguments = supplierInstantiation.getActualTypeArguments();
			return typeArguments.length == 0 ? null : erasedType( typeArguments[0] );
		}
	}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Set the property to one of the accepted shapes: an instance of the supplier, its Class object, or its fully-qualified class name as a String.
  2. Fix the source that coerced the value (XML persistence.xml, YAML map, env-var binder) so the setting reaches Hibernate as a String at minimum.

Example fix

# before (YAML binder delivered an Integer)
hibernate.temporal.changeset_id_supplier: 42

# after
hibernate.temporal.changeset_id_supplier: org.acme.UuidChangesetIdSupplier
Defensive patterns

Strategy: type-guard

Validate before calling

Object v = settings.get("hibernate.temporal.changeset_id_supplier");
if (v != null && !(v instanceof String) && !(v instanceof Class)
        && !(v instanceof org.hibernate.temporal.spi.ChangesetIdentifierSupplier)) {
    throw new IllegalStateException("changeset_id_supplier must be instance, Class, or class name; got " + v.getClass());
}

Type guard

static boolean validSupplierSetting(Object v) {
    return v == null
            || v instanceof org.hibernate.temporal.spi.ChangesetIdentifierSupplier
            || v instanceof Class
            || v instanceof String;
}

Prevention

When it happens

Trigger: Supplying hibernate.temporal.changeset_id_supplier as a non-String, non-Class object: a number or boolean coerced from an XML/YAML property value, a List/Map from a deserialized config, or a java.net.URL/Path produced by system-property handling — none of the three instanceof branches match.

Common situations: persistence.xml <property value="..."> parsed into a primitive by a config framework; YAML/JSON config deserialized into typed values; property placeholders resolved to unexpected types by an environment binder.

Related errors


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