hibernate/hibernate-orm · error · HibernateException

Detected a second LazyServiceResolver replacing an existing

Error message

Detected a second LazyServiceResolver replacing an existing LazyServiceResolver implementation for strategy {}

What it means

Hibernate 6 registers exactly one LazyServiceResolver per lazily handled strategy role (Dialect and JtaPlatform via StrategySelectorBuilder). registerStrategyLazily() throws HibernateException when a second resolver arrives for a role that already has one, because two lazy resolvers cannot be merged and silently replacing the first would hide conflicting integrations.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorImpl.java:208

	private static <T> T create(Class<T> strategyClass) {
		try {
			return strategyClass.getDeclaredConstructor().newInstance();
		}
		catch (Exception e) {
			throw new StrategySelectionException(
					String.format( "Could not instantiate named strategy class [%s]", strategyClass.getName() ),
					e
			);
		}
	}

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Lifecycle

	public <T> void registerStrategyLazily(Class<T> strategy, LazyServiceResolver<T> resolver) {
		final var previous = lazyStrategyImplementorByStrategyMap.put( strategy, resolver );
		if ( previous != null ) {
			throw new HibernateException( "Detected a second LazyServiceResolver replacing an existing LazyServiceResolver implementation for strategy " + strategy.getName() );
		}
	}

	private <T> void contributeImplementation(Class<T> strategy, Class<? extends T> implementation, String... names) {
		final var namedStrategyImplementorMap =
				namedStrategyImplementorByStrategyMap.computeIfAbsent( strategy, clazz -> new ConcurrentHashMap<>() );
		for ( String name : names ) {
			final var old = namedStrategyImplementorMap.put( name, implementation );
			if ( BOOT_LOGGER.isTraceEnabled() ) {
				if ( old == null ) {
					BOOT_LOGGER.strategySelectorMapping(
							strategy.getSimpleName(),
							name,
							implementation.getName()
					);
				}
				else {
					BOOT_LOGGER.strategySelectorMappingReplacing(

View on GitHub (pinned to fad1729dce)

Solutions

  1. Deduplicate hibernate-core on the classpath (dependency:tree, shading rules, server module lists)
  2. Exclude embedded Hibernate classes from the fat jar or mark the dependency as provided
  3. Align all modules on a single Hibernate version
Defensive patterns

Strategy: validation

Validate before calling

// Boot-time guard: exactly one hibernate-core on the classpath
Enumeration<URL> urls = cl.getResources("org/hibernate/Version.class");
List<URL> found = Collections.list(urls);
if (found.size() > 1) {
    throw new IllegalStateException("Multiple hibernate-core copies detected: " + found);
}

Try / catch

try {
    strategySelector.registerStrategyLazily(Dialect.class, resolver);
} catch (HibernateException e) {
    if (e.getMessage().contains("second LazyServiceResolver")) {
        // duplicate Hibernate contributions: audit classpath for embedded/shaded copies
        log.error("Duplicate Hibernate artifacts detected - deduplicate hibernate-core", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Two providers registering a lazy resolver for the same strategy class - in practice almost always Hibernate's own contributions arriving twice: hibernate-core classes embedded in a shaded/fat jar plus the real dependency on the classpath, or duplicate hibernate-core artifacts across classloaders.

Common situations: Uber-jars bundling hibernate-core classes; application servers with Hibernate present in both a server module and the deployment; mixed Hibernate versions across modules; a custom jar copying Hibernate's StrategySelectorBuilder contributions.

Related errors


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