hibernate/hibernate-orm · error · IllegalStateException

No child ServiceRegistry registrations found

Error message

No child ServiceRegistry registrations found

What it means

BootstrapServiceRegistryImpl lazily creates its child-registry set on the first registerChild() call; deRegisterChild() throws IllegalStateException when that set is still null - i.e., a child is being deregistered before any child was ever registered, or after the registry was already destroyed and cleared. In practice StandardServiceRegistry.close() deregisters itself from its parent bootstrap registry, so this signals out-of-order teardown.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/boot/registry/internal/BootstrapServiceRegistryImpl.java:281

				SERVICE_LOGGER.unableToStopService( binding.getServiceRole().getName(), e );
			}
		}
	}

	@Override
	public synchronized void registerChild(@Nonnull ServiceRegistryImplementor child) {
		if ( childRegistries == null ) {
			childRegistries = new HashSet<>();
		}
		if ( !childRegistries.add( child ) ) {
			SERVICE_LOGGER.childAlreadyRegistered( child );
		}
	}

	@Override
	public synchronized void deRegisterChild(@Nonnull ServiceRegistryImplementor child) {
		if ( childRegistries == null ) {
			throw new IllegalStateException( "No child ServiceRegistry registrations found" );
		}
		childRegistries.remove( child );
		if ( childRegistries.isEmpty() ) {
			if ( autoCloseRegistry ) {
				SERVICE_LOGGER.destroyingBootstrapRegistry();
				destroy();
			}
			else {
				SERVICE_LOGGER.skippingBootstrapRegistryDestruction();
			}
		}
	}

	@Override
	public <T extends Service> T fromRegistryOrChildren(@Nonnull Class<T> serviceRole) {
		return AbstractServiceRegistryImpl.fromRegistryOrChildren( serviceRole, this, childRegistries );
	}
}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Close exactly once in the correct order: SessionFactory, then its StandardServiceRegistry, then let the bootstrap registry auto-close when the last child deregisters
  2. Guard teardown with isActive() checks and avoid manually destroying a bootstrap registry that still has live children
  3. In tests, use try-with-resources or lifecycle extensions that own the whole chain

Example fix

// before
bootstrapRegistry.destroy();          // destroys parent first
standardRegistry.close();              // -> IllegalStateException in deRegisterChild

// after
standardRegistry.close();              // child first; bootstrap auto-closes when empty
// no manual bootstrapRegistry.destroy() needed
Defensive patterns

Strategy: validation

Validate before calling

// Close-order guard: only close a child registry while the parent is still active
if (standardRegistry.isActive() && bootstrapRegistry.isActive()) {
    standardRegistry.close(); // deregisters from bootstrap; bootstrap auto-closes when empty
}

Try / catch

try {
    standardRegistry.close();
} catch (IllegalStateException e) {
    if (e.getMessage().contains("No child ServiceRegistry registrations")) {
        // already deregistered/destroyed: nothing left to do, ignore
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Closing a StandardServiceRegistry after its parent BootstrapServiceRegistry was already destroyed (child set gone), or calling deRegisterChild directly on a bootstrap registry that never registered children; also double-close sequences where the registry already destroyed itself after the last child deregistered (autoCloseRegistry).

Common situations: Double-close of SessionFactory/registry chains; tests that manually destroy the bootstrap registry and then close child factories; framework restart code closing registries in the wrong order.

Related errors


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