{"record":{"id":"1212a5466bf66841","repo":"brettwooldridge/HikariCP","slug":"hikaridatasource-datasource-has-been-closed","errorCode":null,"errorMessage":"HikariDataSource ${dataSource} has been closed.","messagePattern":"HikariDataSource (.+?) has been closed\\.","errorType":"exception","errorClass":"SQLException","httpStatus":null,"severity":"error","filePath":"src/main/java/com/zaxxer/hikari/HikariDataSource.java","lineNumber":95,"sourceCode":"      configuration.copyStateTo(this);\n\n      LOGGER.info(\"{} - Starting...\", configuration.getPoolName());\n      pool = fastPathPool = new HikariPool(this);\n      LOGGER.info(\"{} - Start completed.\", configuration.getPoolName());\n\n      this.seal();\n   }\n\n   // ***********************************************************************\n   //                          DataSource methods\n   // ***********************************************************************\n\n   /** {@inheritDoc} */\n   @Override\n   public Connection getConnection() throws SQLException\n   {\n      if (isClosed()) {\n         throw new SQLException(\"HikariDataSource \" + this + \" has been closed.\");\n      }\n\n      if (fastPathPool != null) {\n         return fastPathPool.getConnection();\n      }\n\n      // See http://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java\n      HikariPool result = pool;\n      if (result == null) {\n         synchronized (this) {\n            result = pool;\n            if (result == null) {\n               validate();\n               LOGGER.info(\"{} - Starting...\", getPoolName());\n               try {\n                  pool = result = new HikariPool(this);\n                  this.seal();\n               }","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/brettwooldridge/HikariCP/blob/a4d93f4f85517f90e632b795486d7102e933d7ff/src/main/java/com/zaxxer/hikari/HikariDataSource.java#L77-L113","documentation":"HikariDataSource.getConnection() checks isClosed() and throws SQLException if the pool was already shut down. The pool is sealed/closed either by an explicit close() call or by JVM shutdown hooks, so any subsequent connection request fails immediately.","triggerScenarios":"Calling ds.getConnection() after ds.close(); a Spring context refresh/reload that closes the old bean while application code still holds the old reference; a shutdown hook firing while background threads still borrow connections; storing the DataSource statically and outliving container lifecycle.","commonSituations":"Hot redeploy in dev, @PreDestroy/close ordering bugs, sharing one HikariDataSource across application restarts, integration tests that close the context between test methods but reuse helpers holding the DataSource.","solutions":["Ensure getConnection() is never called after close(): re-obtain the DataSource from the container/context instead of caching a stale instance","Audit close() calls and shutdown hooks; only close the pool when the application truly stops","In Spring, mark the pool as a container-managed bean and never call close() manually","If a background thread borrows connections, shut it down (or latch it) before closing the pool","As a defensive measure, check isClosed() before borrowing and rebuild the pool if closed (self-healing wrapper)"],"exampleFix":"// before\nstatic DataSource DS = createPool(); // cached forever\n... later, after DS.close(): DS.getConnection(); // SQLException\n\n// after\nDataSource ds = context.getBean(HikariDataSource.class); // always fresh from context\nif (ds instanceof HikariDataSource hds && hds.isClosed()) {\n   throw new IllegalStateException(\"pool closed; re-create it\");\n}","handlingStrategy":"validation","validationCode":"if (ds instanceof HikariDataSource hds && hds.isClosed()) {\n    // rebuild or fetch a live DataSource instead of calling getConnection()\n    throw new IllegalStateException(\"HikariDataSource closed; obtain a new instance\");\n}","typeGuard":null,"tryCatchPattern":"try { conn = ds.getConnection(); }\ncatch (SQLException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"has been closed\")) {\n        // refresh DataSource reference / re-init pool\n    }\n    throw e;\n}","preventionTips":["Do not cache HikariDataSource in static fields across container restarts","Close pools only in application shutdown hooks / @PreDestroy after workers stop","Check isClosed() before borrowing from long-lived references"],"tags":["hikaricp","pool","lifecycle","connection"],"backgroundTag":null,"analyzedSha":"a4d93f4f85517f90e632b795486d7102e933d7ff","analyzedAt":"2026-08-14T12:11:37.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}