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

  1. Avoid sharing a Connection across threads; the holder-null race is typically a concurrency artefact.
  2. Scope every Connection in try-with-resources so it cannot outlive its holder.
  3. If this appears with a chained disableError, treat it like error 57 — the underlying cause explains the reclamation.
  4. 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

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


AI-assisted analysis of alibaba/druid@fa8dc99126 (2026-08-14). Data as JSON: /api/errors/ad7375b7ebfc2262. Report an issue: GitHub.