brettwooldridge/HikariCP · error · IllegalStateException

MetricsTrackerFactory can only be set one time

Error message

MetricsTrackerFactory can only be set one time

What it means

setMetricsTrackerFactory() can only be assigned once before/while the pool starts; if a factory is already set and the pool exists, HikariDataSource throws IllegalStateException. The tracker factory is bound into the pool's metrics lifecycle at startup and cannot be swapped afterwards.

Source

Thrown at src/main/java/com/zaxxer/hikari/HikariDataSource.java:259

            throw new IllegalStateException("MetricRegistry can only be set one time");
         }
         else {
            p.setMetricRegistry(super.getMetricRegistry());
         }
      }
   }

   /** {@inheritDoc} */
   @Override
   public void setMetricsTrackerFactory(MetricsTrackerFactory metricsTrackerFactory)
   {
      var isAlreadySet = getMetricsTrackerFactory() != null;
      super.setMetricsTrackerFactory(metricsTrackerFactory);

      var p = pool;
      if (p != null) {
         if (isAlreadySet) {
            throw new IllegalStateException("MetricsTrackerFactory can only be set one time");
         }
         else {
            p.setMetricsTrackerFactory(super.getMetricsTrackerFactory());
         }
      }
   }

   /** {@inheritDoc} */
   @Override
   public void setHealthCheckRegistry(Object healthCheckRegistry)
   {
      var isAlreadySet = getHealthCheckRegistry() != null;
      super.setHealthCheckRegistry(healthCheckRegistry);

      var p = pool;
      if (p != null) {
         if (isAlreadySet) {
            throw new IllegalStateException("HealthCheckRegistry can only be set one time");

View on GitHub (pinned to a4d93f4f85)

Solutions

  1. Set metricsTrackerFactory exactly once, before first connection acquisition
  2. Ensure metricRegistry and metricsTrackerFactory are not both being set by different components
  3. To replace the factory, tear down and rebuild the DataSource
  4. Configure it via HikariConfig before constructing HikariDataSource(config)

Example fix

// before
ds.setMetricsTrackerFactory(factoryA);
ds.setMetricsTrackerFactory(factoryB); // IllegalStateException

// after
HikariConfig cfg = new HikariConfig();
cfg.setMetricsTrackerFactory(factoryB); // single assignment pre-start
HikariDataSource ds = new HikariDataSource(cfg);
Defensive patterns

Strategy: validation

Validate before calling

if (ds.getMetricsTrackerFactory() == null && ds.getMetricRegistry() == null) {
    ds.setMetricsTrackerFactory(factory);
}

Prevention

When it happens

Trigger: Calling setMetricsTrackerFactory(...) twice on a live pool; specifying both metricRegistry and metricsTrackerFactory (framework may set one, your code the other); Prometheus/micrometer glue re-registering the factory on refresh.

Common situations: Custom MetricsTrackerFactory for Prometheus, repeated initialization during Spring context refresh, actuator endpoint that rebinds metrics.

Related errors


AI-assisted analysis of brettwooldridge/HikariCP@a4d93f4f85 (2026-08-14). Data as JSON: /api/errors/4b9680b9a1deea44. Report an issue: GitHub.