alibaba/druid · error · SQLException
connection holder is null
Error message
connection holder is null
What it means
Thrown by DruidPooledConnection.checkStateInternal() when the connection is neither closed nor disabled but its holder is null — meaning the DruidConnectionHolder backing this pooled connection has been detached. If a disableError exists it is chained; otherwise thrown bare. This is an inconsistent state: the pooled wrapper exists but has no underlying physical connection handle.
Source
Thrown at core/src/main/java/com/alibaba/druid/pool/DruidPooledConnection.java:1192
if (closed) {
if (disableError != null) {
throw new SQLException("connection closed", disableError);
} else {
throw new SQLException("connection closed");
}
}
if (disable) {
if (disableError != null) {
throw new SQLException("connection disabled", disableError);
} else {
throw new SQLException("connection disabled");
}
}
if (holder == null) {
if (disableError != null) {
throw new SQLException("connection holder is null", disableError);
} else {
throw new SQLException("connection holder is null");
}
}
}
public String toString() {
if (conn != null) {
return conn.toString();
} else {
return "closed-conn-" + System.identityHashCode(this);
}
}
public void setSchema(String schema) throws SQLException {
if (JdbcUtils.isMysqlDbType(holder.dataSource.getDbType())) {
if (holder.initSchema == null) {
holder.initSchema = conn.getSchema();View on GitHub (pinned to fa8dc99126)
Solutions
- Avoid sharing a Connection across threads; the holder-null race is typically a concurrency artefact.
- Scope every Connection in try-with-resources so it cannot outlive its holder.
- If this appears with a chained disableError, treat it like error 57 — the underlying cause explains the reclamation.
- Upgrade Druid if holder-null-without-cause appears: it usually indicates a lifecycle race fixed in newer versions.
Example fix
// before — shared connection, holder nulled by another thread
private Connection shared;
void t1() { shared = dataSource.getConnection(); }
void t2() { shared.createStatement(); } // holder null -> SQLException
// after — per-thread borrow
void run() {
try (Connection c = dataSource.getConnection(); Statement s = c.createStatement()) {
s.execute(SQL);
}
} Defensive patterns
Strategy: validation
Validate before calling
if (pooledConn.getHolder() == null) {
Throwable why = pooledConn.getDisableError();
throw new IllegalStateException("holder detached" + (why == null ? "" : ": " + why));
}
// proceed Type guard
boolean usable = pooledConn != null && pooledConn.getHolder() != null
&& !pooledConn.isClosed() && !pooledConn.isDisable(); Try / catch
try {
pooledConn.createStatement();
} catch (SQLException e) {
if ("connection holder is null".equals(e.getMessage())) {
// inconsistent state; abandon this wrapper and borrow fresh
log.error("pooled conn holder detached; state race?", e.getCause());
borrowFreshAndRetry();
} else throw e;
} Prevention
- Never share a Connection across threads — holder-null is usually a concurrency race.
- Scope every Connection in try-with-resources.
- Upgrade Druid if holder-null-without-cause appears in single-threaded code.
When it happens
Trigger: JDBC operation on a DruidPooledConnection where holder == null (closed and disable both false). Line 1192 (with cause) or line 1194 (without) throws. Occurs when the holder was cleared (e.g. after the physical connection was reclaimed) but the wrapper was not marked closed/disabled, or when a Filter/proxy detached the holder.
Common situations: Concurrent close racing with use such that holder is nulled before closed is set; a Filter or application code calling setHolder(null)-equivalent paths; using a connection after the pool reclaimed the underlying physical connection; a bug in custom connection wrapping.
Related errors
- dataSource already closed at {date}
- connection closed
- validationQuery didn't return a row
- dataSource inited.
- can not restart, activeCount not zero. {}
AI-assisted analysis of alibaba/druid@fa8dc99126 (2026-08-14).
Data as JSON: /api/errors/ad7375b7ebfc2262.
Report an issue: GitHub.