hibernate/hibernate-orm · error · MappingException

Settings 'hibernate.temporal.use_server_transaction_timestam

Error message

Settings 'hibernate.temporal.use_server_transaction_timestamps' and 'hibernate.temporal.changeset_id_supplier' are mutually exclusive

What it means

The temporal (versioned-data) coordinator decides at bootstrap how changeset identifiers are produced. hibernate.temporal.use_server_transaction_timestamps=true derives ids from the database's current timestamp; hibernate.temporal.changeset_id_supplier delegates generation to a custom supplier. Both present is contradictory — two competing id sources — so ChangesetCoordinatorImpl throws a MappingException during SessionFactory construction.

Source

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

 *
 * @since 7.4
 */
public class ChangesetCoordinatorImpl
		implements ChangesetCoordinator, ChangesetIdentifierSupplier<Instant> {

	private Class<?> identifierValueType;
	private ChangesetIdentifierSupplier<?> identifierSupplier;
	private final boolean useServerTransactionTimestamps;

	public ChangesetCoordinatorImpl(ServiceRegistry serviceRegistry) {
		final var settings =
				serviceRegistry.requireService( ConfigurationService.class )
						.getSettings();
		useServerTransactionTimestamps =
				getBoolean( USE_SERVER_TRANSACTION_TIMESTAMPS, settings );
		if ( useServerTransactionTimestamps ) {
			if ( settings.containsKey( CHANGESET_ID_SUPPLIER ) ) {
				throw new MappingException( "Settings '"
											+ USE_SERVER_TRANSACTION_TIMESTAMPS + "' and '"
											+ CHANGESET_ID_SUPPLIER + "' are mutually exclusive"
				);
			}
			final var dialect = serviceRegistry.requireService( JdbcServices.class ).getDialect();
			identifierSupplier = dialect.isCurrentTimestampStable()
					? null
					: new CurrentTimestampChangesetIdentifierSupplier();
			identifierValueType = Instant.class;
		}
		else {
			identifierSupplier =
					resolveSupplier( settings,
							serviceRegistry.requireService( StrategySelector.class ) );
			identifierValueType = resolveSuppliedType( supplierClass( identifierSupplier ) );
		}
	}

View on GitHub (pinned to fad1729dce)

Solutions

  1. If you want server transaction timestamps, remove the hibernate.temporal.changeset_id_supplier entry entirely.
  2. If you want the custom supplier, remove hibernate.temporal.use_server_transaction_timestamps (or leave it unset/false).

Example fix

# before
hibernate.temporal.use_server_transaction_timestamps=true
hibernate.temporal.changeset_id_supplier=org.acme.UuidSupplier

# after
hibernate.temporal.changeset_id_supplier=org.acme.UuidSupplier
Defensive patterns

Strategy: validation

Validate before calling

boolean useServerTs = Boolean.parseBoolean(
        String.valueOf(settings.getOrDefault("hibernate.temporal.use_server_transaction_timestamps", "false")));
if (useServerTs && settings.containsKey("hibernate.temporal.changeset_id_supplier")) {
    throw new IllegalStateException(
        "Pick one: server transaction timestamps OR a changeset id supplier, not both");
}

Prevention

When it happens

Trigger: A settings map, persistence.xml, or properties file containing both hibernate.temporal.use_server_transaction_timestamps=true and any value (instance, Class, or class name) under hibernate.temporal.changeset_id_supplier; the constructor's containsKey check fires immediately.

Common situations: Copy-pasting properties from two different temporal-versioning examples; enabling a preset bundle of temporal settings without pruning; config templates where the supplier was the old approach and server timestamps the newer one.

Related errors


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