hibernate/hibernate-orm · error · NullSynchronizationException

Synchronization to register cannot be null

Error message

Synchronization to register cannot be null

What it means

SynchronizationRegistryStandardImpl.registerSynchronization(Synchronization) explicitly rejects a null argument by throwing NullSynchronizationException ("Synchronization to register cannot be null"), described in Hibernate as a glorified NullPointerException. It is a fail-fast guard on the transaction SPI: a null JTA Synchronization can never be notified, so registration is refused immediately.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/resource/transaction/internal/SynchronizationRegistryStandardImpl.java:37

 * @author Steve Ebersole
 */
public class SynchronizationRegistryStandardImpl implements SynchronizationRegistryImplementor {

	private LinkedHashSet<Synchronization> synchronizations;

	/**
	 * Intended for test access
	 *
	 * @return The number of Synchronizations registered
	 */
	public int getNumberOfRegisteredSynchronizations() {
		return synchronizations == null ? 0 : synchronizations.size();
	}

	@Override
	public void registerSynchronization(Synchronization synchronization) {
		if ( synchronization == null ) {
			throw new NullSynchronizationException();
		}

		if ( synchronizations == null ) {
			synchronizations = new LinkedHashSet<>();
		}

		final boolean added = synchronizations.add( synchronization );
		if ( !added ) {
			SYNCHRONIZATION_LOGGER.synchronizationAlreadyRegistered( synchronization );
		}
	}

	@Override
	public void notifySynchronizationsBeforeTransactionCompletion() {
		SYNCHRONIZATION_LOGGER.notifyingSynchronizationsBefore();
		if ( synchronizations != null ) {
			for ( var synchronization : synchronizations ) {
				try {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Null-check the Synchronization before calling registerSynchronization
  2. Fix the producer/factory that returns null so it always returns a real Synchronization
  3. Only register synchronizations after the transaction has started, from code that can construct the callback reliably

Example fix

// before
transaction.registerSynchronization(maybeCreateListener()); // may return null

// after
final var listener = maybeCreateListener();
if (listener != null) {
    transaction.registerSynchronization(listener);
}
Defensive patterns

Strategy: validation

Validate before calling

final Synchronization sync = listenerFactory.create();
if (sync != null) {
    transaction.registerSynchronization(sync);
}
else {
    LOG.debug("no synchronization produced; skipping registration");
}

Type guard

static Synchronization orNull(Synchronization s) { return s; }
// simply: guard with `s != null` before registerSynchronization

Try / catch

try {
    transaction.registerSynchronization(sync);
}
catch (NullSynchronizationException e) {
    // programming bug: producer returned null; fix the producer
    throw new IllegalStateException("listener factory returned null synchronization", e);
}

Prevention

When it happens

Trigger: Calling Transaction.registerSynchronization(null), or passing the result of a supplier/factory method that returned null — e.g. a conditional listener builder whose branch returns null, or dependency injection that failed to produce the Synchronization bean.

Common situations: Custom integrators/interceptors registering listeners only in some environments; Spring or CDI producing a null bean for a Synchronization; code copied from tests where the callback was optional.

Related errors


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