hibernate/hibernate-orm · error · HibernateException

Multiple StatisticsFactory service registrations found via S

Error message

Multiple StatisticsFactory service registrations found via ServiceLoader; specify one explicitly via 'hibernate.stats.factory'

What it means

When hibernate.stats.factory is not set, StatisticsInitiator discovers StatisticsFactory implementations via java.util.ServiceLoader (META-INF/services/org.hibernate.stat.spi.StatisticsFactory). Finding more than one registration is ambiguous — Hibernate cannot choose which factory builds Statistics — so bootstrap fails with this HibernateException rather than guessing.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsInitiator.java:88

			catch (HibernateException e) {
				throw e;
			}
			catch (Exception e) {
				throw new HibernateException(
						"Unable to instantiate specified StatisticsFactory implementation [" + configValue + "]",
						e
				);
			}
		}
	}

	private static @Nullable StatisticsFactory discover(@Nonnull ClassLoaderService classLoaderService) {
		final var discovered = classLoaderService.loadJavaServices( StatisticsFactory.class );
		final var iterator = discovered.iterator();
		if ( iterator.hasNext() ) {
			final var selected = iterator.next();
			if ( iterator.hasNext() ) {
				throw new HibernateException(
						"Multiple StatisticsFactory service registrations found via ServiceLoader; "
						+ "specify one explicitly via '" + STATS_BUILDER + "'" );
			}
			return selected;
		}
		else {
			return null;
		}
	}
}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Set hibernate.stats.factory explicitly to the implementation you want — an explicit setting bypasses ServiceLoader discovery entirely.
  2. Remove the redundant provider: exclude the duplicate dependency, or strip one META-INF/services/org.hibernate.stat.spi.StatisticsFactory entry from your packaging.

Example fix

# before
# two jars each provide META-INF/services/org.hibernate.stat.spi.StatisticsFactory -> boot fails

# after
<property name="hibernate.stats.factory" value="org.acme.MetricsStatisticsFactory"/>
Defensive patterns

Strategy: try-catch

Validate before calling

long providers = java.util.ServiceLoader
        .load(org.hibernate.stat.spi.StatisticsFactory.class,
              Thread.currentThread().getContextClassLoader())
        .stream().count();
if (providers > 1) {
    props.put("hibernate.stats.factory", "org.acme.MetricsStatisticsFactory"); // disambiguate before boot
}

Try / catch

try {
    sessionFactory = cfg.buildSessionFactory();
} catch (HibernateException e) {
    if (e.getMessage() != null && e.getMessage().contains("Multiple StatisticsFactory")) {
        // set hibernate.stats.factory explicitly and rebuild
    }
    throw e;
}

Prevention

When it happens

Trigger: Two jars on the classpath each shipping a META-INF/services/org.hibernate.stat.spi.StatisticsFactory entry: the discover() helper loads all registrations, sees a second one after the first, and throws during SessionFactory startup.

Common situations: Adding a telemetry/monitoring jar that also registers a StatisticsFactory while another integration is already present; duplicate versions of the same integration jar after a dependency merge; transitive dependencies silently pulling a second provider.

Related errors


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