mybatis/mybatis-3 · critical · SQLException
PooledDataSource: Unknown severe error condition. The conne
Error message
PooledDataSource: Unknown severe error condition. The connection pool returned a null connection.
What it means
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.
Source
Thrown at src/main/java/org/apache/ibatis/datasource/pooled/PooledDataSource.java:546
if (localBadConnectionCount > poolMaximumIdleConnections + poolMaximumLocalBadConnectionTolerance) {
if (log.isDebugEnabled()) {
log.debug("PooledDataSource: Could not get a good connection to the database.");
}
throw new SQLException("PooledDataSource: Could not get a good connection to the database.");
}
}
}
} finally {
lock.unlock();
}
}
if (conn == null) {
if (log.isDebugEnabled()) {
log.debug("PooledDataSource: Unknown severe error condition. The connection pool returned a null connection.");
}
throw new SQLException(
"PooledDataSource: Unknown severe error condition. The connection pool returned a null connection.");
}
return conn;
}
/**
* Method to check to see if a connection is still usable
*
* @param conn
* - the connection to check
*
* @return True if the connection is still usable
*/
protected boolean pingConnection(PooledConnection conn) {
boolean result;
try {View on GitHub (pinned to 008069adb1)
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
Example fix
// before: leak exhausts pool -> null/failed getConnection
Connection c = dataSource.getConnection();
if (someCondition) return; // never closed
// after
try (Connection c = dataSource.getConnection()) {
if (someCondition) return; // closed by try-with-resources
} Defensive patterns
Strategy: retry
Validate before calling
// Detect pool exhaustion early by monitoring leased vs active counts:
PooledDataSource pds = (PooledDataSource) dataSource;
PoolState state = pds.getPoolState();
if (state.getActiveConnectionCount() >= pds.getPoolMaximumActiveConnections()) {
// pool exhausted: likely leak — log stack traces, alert, do not block indefinitely
} Try / catch
try {
conn = dataSource.getConnection();
} catch (SQLException e) {
if (e.getMessage().contains("returned a null connection")) {
// exhaustive condition: check for leaks, then retry after freeing connections
} else throw e;
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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).
Related errors
- A Cursor is already closed.
- Error accessing PooledConnection. Connection is invalid.
- PooledDataSource: Could not get a good connection to the dat
- Unknown execution method for: {name}
- Mapper method '{name}' attempted to return null from a metho
AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14).
Data as JSON: /api/errors/fb077f02d7945f17.
Report an issue: GitHub.