brettwooldridge/HikariCP · error · IllegalStateException

MetricRegistry can only be set one time

Error message

MetricRegistry can only be set one time

What it means

setMetricRegistry() on HikariDataSource refuses to change the metric registry once the pool has been started and a registry was already set. HikariCP wires metrics into the live pool at startup, so re-assigning the registry afterwards would silently produce wrong metrics; it throws IllegalStateException instead.

Source

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

      return false;
   }

   // ***********************************************************************
   //                        HikariConfigMXBean methods
   // ***********************************************************************

   /** {@inheritDoc} */
   @Override
   public void setMetricRegistry(Object metricRegistry)
   {
      var isAlreadySet = getMetricRegistry() != null;
      super.setMetricRegistry(metricRegistry);

      var p = pool;
      if (p != null) {
         if (isAlreadySet) {
            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");

View on GitHub (pinned to a4d93f4f85)

Solutions

  1. Set the metric registry once, before the first getConnection() (i.e., before pool initialization)
  2. Remove duplicate configuration paths that set the registry (check both your code and framework autoconfiguration)
  3. If you must change registries, close the DataSource, create a new one configured correctly, and swap it
  4. Set spring.datasource.hikari.* properties (or the equivalent) declaratively so ordering is deterministic

Example fix

// before
HikariDataSource ds = new HikariDataSource(config);
ds.getConnection(); // pool starts
ds.setMetricRegistry(registry); // second set -> IllegalStateException

// after
config.setMetricRegistry(registry); // before startup
HikariDataSource ds = new HikariDataSource(config);
Defensive patterns

Strategy: validation

Validate before calling

// set registry once, before pool start
HikariConfig cfg = new HikariConfig();
cfg.setMetricRegistry(registry);
// assert getMetricRegistry() == null before calling setter on an existing DS
if (ds.getMetricRegistry() != null) { /* skip: already bound */ }

Prevention

When it happens

Trigger: Calling setMetricRegistry(...) twice while the pool is running; a framework (Spring Boot metrics, Dropwizard) injecting the registry in a @PostConstruct that runs after the pool lazily started; reconfiguring metrics at runtime via JMX/actuator.

Common situations: Spring Boot actuator + custom MetricRegistry bean, micrometer migration re-binding registries, dev hot-reload re-running configuration against the same live DataSource.

Related errors


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