{"record":{"id":"4b9680b9a1deea44","repo":"brettwooldridge/HikariCP","slug":"metricstrackerfactory-can-only-be-set-one-time","errorCode":null,"errorMessage":"MetricsTrackerFactory can only be set one time","messagePattern":"MetricsTrackerFactory can only be set one time","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"src/main/java/com/zaxxer/hikari/HikariDataSource.java","lineNumber":259,"sourceCode":"            throw new IllegalStateException(\"MetricRegistry can only be set one time\");\n         }\n         else {\n            p.setMetricRegistry(super.getMetricRegistry());\n         }\n      }\n   }\n\n   /** {@inheritDoc} */\n   @Override\n   public void setMetricsTrackerFactory(MetricsTrackerFactory metricsTrackerFactory)\n   {\n      var isAlreadySet = getMetricsTrackerFactory() != null;\n      super.setMetricsTrackerFactory(metricsTrackerFactory);\n\n      var p = pool;\n      if (p != null) {\n         if (isAlreadySet) {\n            throw new IllegalStateException(\"MetricsTrackerFactory can only be set one time\");\n         }\n         else {\n            p.setMetricsTrackerFactory(super.getMetricsTrackerFactory());\n         }\n      }\n   }\n\n   /** {@inheritDoc} */\n   @Override\n   public void setHealthCheckRegistry(Object healthCheckRegistry)\n   {\n      var isAlreadySet = getHealthCheckRegistry() != null;\n      super.setHealthCheckRegistry(healthCheckRegistry);\n\n      var p = pool;\n      if (p != null) {\n         if (isAlreadySet) {\n            throw new IllegalStateException(\"HealthCheckRegistry can only be set one time\");","sourceCodeStart":241,"sourceCodeEnd":277,"githubUrl":"https://github.com/brettwooldridge/HikariCP/blob/a4d93f4f85517f90e632b795486d7102e933d7ff/src/main/java/com/zaxxer/hikari/HikariDataSource.java#L241-L277","documentation":"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.","triggerScenarios":"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.","commonSituations":"Custom MetricsTrackerFactory for Prometheus, repeated initialization during Spring context refresh, actuator endpoint that rebinds metrics.","solutions":["Set metricsTrackerFactory exactly once, before first connection acquisition","Ensure metricRegistry and metricsTrackerFactory are not both being set by different components","To replace the factory, tear down and rebuild the DataSource","Configure it via HikariConfig before constructing HikariDataSource(config)"],"exampleFix":"// before\nds.setMetricsTrackerFactory(factoryA);\nds.setMetricsTrackerFactory(factoryB); // IllegalStateException\n\n// after\nHikariConfig cfg = new HikariConfig();\ncfg.setMetricsTrackerFactory(factoryB); // single assignment pre-start\nHikariDataSource ds = new HikariDataSource(cfg);","handlingStrategy":"validation","validationCode":"if (ds.getMetricsTrackerFactory() == null && ds.getMetricRegistry() == null) {\n    ds.setMetricsTrackerFactory(factory);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Set metricsTrackerFactory exactly once pre-start","Do not mix metricRegistry and metricsTrackerFactory on the same pool","Centralize metrics wiring in one configuration class"],"tags":["hikaricp","metrics","configuration","lifecycle"],"backgroundTag":null,"analyzedSha":"a4d93f4f85517f90e632b795486d7102e933d7ff","analyzedAt":"2026-08-14T12:11:37.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}