{"record":{"id":"fb077f02d7945f17","repo":"mybatis/mybatis-3","slug":"pooleddatasource-unknown-severe-error-condition","errorCode":null,"errorMessage":"PooledDataSource: Unknown severe error condition.  The connection pool returned a null connection.","messagePattern":"PooledDataSource: Unknown severe error condition\\.  The connection pool returned a null connection\\.","errorType":"exception","errorClass":"SQLException","httpStatus":null,"severity":"critical","filePath":"src/main/java/org/apache/ibatis/datasource/pooled/PooledDataSource.java","lineNumber":546,"sourceCode":"            if (localBadConnectionCount > poolMaximumIdleConnections + poolMaximumLocalBadConnectionTolerance) {\n              if (log.isDebugEnabled()) {\n                log.debug(\"PooledDataSource: Could not get a good connection to the database.\");\n              }\n              throw new SQLException(\"PooledDataSource: Could not get a good connection to the database.\");\n            }\n          }\n        }\n      } finally {\n        lock.unlock();\n      }\n\n    }\n\n    if (conn == null) {\n      if (log.isDebugEnabled()) {\n        log.debug(\"PooledDataSource: Unknown severe error condition.  The connection pool returned a null connection.\");\n      }\n      throw new SQLException(\n          \"PooledDataSource: Unknown severe error condition.  The connection pool returned a null connection.\");\n    }\n\n    return conn;\n  }\n\n  /**\n   * Method to check to see if a connection is still usable\n   *\n   * @param conn\n   *          - the connection to check\n   *\n   * @return True if the connection is still usable\n   */\n  protected boolean pingConnection(PooledConnection conn) {\n    boolean result;\n\n    try {","sourceCodeStart":528,"sourceCodeEnd":564,"githubUrl":"https://github.com/mybatis/mybatis-3/blob/008069adb1b089579b5dcba87ee591908b263274/src/main/java/org/apache/ibatis/datasource/pooled/PooledDataSource.java#L528-L564","documentation":"After PooledDataSource.popConnection() exits its lock-protected retry loop without throwing, conn must be non-null. This exception ('Unknown severe error condition. The connection pool returned a null connection.') is a defensive assertion that fires if the loop terminates with no connection and no other exception — i.e., the pool state reached a combination the implementation considers impossible. In practice it indicates a bug-level anomaly: interrupted waits, race in pool state, or a misconfigured pool where active connections were never available.","triggerScenarios":"All pool slots busy and wait timeouts expiring in an unexpected path; thread interruption (InterruptedException) during the connection wait loop; concurrent forceCloseAll racing with popConnection; extremely small pool (poolMaximumActiveConnections exhausted by leaked connections that are never returned).","commonSituations":"Connection leaks: code obtains connections from PooledDataSource directly and never closes them, exhausting the pool until callers fail; application shutdown racing in-flight getConnection calls; JVM thread interrupts (e.g., timed async frameworks cancelling tasks blocked on getConnection).","solutions":["Check for connection leaks first: every raw Connection from PooledDataSource must be closed (try-with-resources); leaked connections exhaust the pool","Review pool sizing: poolMaximumActiveConnections and poolTimeToWait must cover peak concurrency","Ensure forceCloseAll()/shutdown is not racing live traffic (drain requests before closing the pool)","Avoid interrupting threads blocked in getConnection; if using async frameworks, wrap DB access so cancellation cannot interrupt the pool wait","Upgrade MyBatis if on an old release — pool null-path handling has seen fixes"],"exampleFix":"// before: leak exhausts pool -> null/failed getConnection\nConnection c = dataSource.getConnection();\nif (someCondition) return; // never closed\n\n// after\ntry (Connection c = dataSource.getConnection()) {\n  if (someCondition) return; // closed by try-with-resources\n}","handlingStrategy":"retry","validationCode":"// Detect pool exhaustion early by monitoring leased vs active counts:\nPooledDataSource pds = (PooledDataSource) dataSource;\nPoolState state = pds.getPoolState();\nif (state.getActiveConnectionCount() >= pds.getPoolMaximumActiveConnections()) {\n  // pool exhausted: likely leak — log stack traces, alert, do not block indefinitely\n}","typeGuard":null,"tryCatchPattern":"try {\n  conn = dataSource.getConnection();\n} catch (SQLException e) {\n  if (e.getMessage().contains(\"returned a null connection\")) {\n    // exhaustive condition: check for leaks, then retry after freeing connections\n  } else throw e;\n}","preventionTips":["Always close connections you obtain directly (try-with-resources)","Alert when active connections approach poolMaximumActiveConnections — that is the leak signal","Set a sane poolTimeToWait so blocked callers fail fast with a diagnosable error"],"tags":["mybatis","connection-pool","resource-leak","pool-exhaustion","assertion"],"backgroundTag":null,"analyzedSha":"008069adb1b089579b5dcba87ee591908b263274","analyzedAt":"2026-08-14T13:07:10.264Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}