alibaba/druid · error · SQLException

Error

Error message

Error

What it means

Thrown by DruidAbstractDataSource.handleConnectionException() when a non-SQLException Throwable escapes from a pooled connection operation. Druid wraps it in SQLException("Error", t) so callers that only catch SQLException still see it. The 'Error' literal is intentionally generic because the original is not a SQL error type.

Source

Thrown at core/src/main/java/com/alibaba/druid/pool/DruidDataSource.java:1810

        lastErrorTimeMillis = System.currentTimeMillis();

        if (t instanceof SQLException) {
            SQLException sqlEx = (SQLException) t;

            // broadcastConnectionError
            ConnectionEvent event = new ConnectionEvent(pooledConnection, sqlEx);
            for (ConnectionEventListener eventListener : holder.getConnectionEventListeners()) {
                eventListener.connectionErrorOccurred(event);
            }

            // exceptionSorter.isExceptionFatal
            if (exceptionSorter != null && exceptionSorter.isExceptionFatal(sqlEx)) {
                handleFatalError(pooledConnection, sqlEx, sql);
            }

            throw sqlEx;
        } else {
            throw new SQLException("Error", t);
        }
    }

    protected final void handleFatalError(
            DruidPooledConnection conn,
            SQLException error,
            String sql
    ) throws SQLException {
        final DruidConnectionHolder holder = conn.holder;

        if (conn.isTraceEnable()) {
            activeConnectionLock.lock();
            try {
                if (conn.isTraceEnable()) {
                    activeConnections.remove(conn);
                    conn.setTraceEnable(false);
                }
            } finally {

View on GitHub (pinned to fa8dc99126)

Solutions

  1. Inspect getCause() of the thrown SQLException — it holds the real non-SQL Throwable; fix that root problem.
  2. If a custom Filter throws, have it wrap its failures in SQLException so they propagate cleanly instead of being re-wrapped as 'Error'.
  3. Guard JDBC usage so only SQLException is expected; treat any other Throwable as a serious bug (Error subclass) needing JVM-level attention.

Example fix

// before — filter throws RuntimeException, surfaces as SQLException("Error")
public class MyFilter extends FilterAdapter {
    public void statementExecuteUpdate(FilterChain c, StatementProxy s, String sql) {
        throw new RuntimeException("boom");
    }
}

// after — throw SQLException so callers get a typed SQL failure
throw new SQLException("boom", e);
Defensive patterns

Strategy: try-catch

Type guard

// narrow: only SQL exceptions are expected from JDBC
boolean isSql = (t instanceof SQLException);

Try / catch

try {
    doJdbcWork(conn);
} catch (SQLException e) {
    if ("Error".equals(e.getMessage()) && e.getCause() != null
            && !(e.getCause() instanceof SQLException)) {
        Throwable real = e.getCause();
        log.error("non-SQL failure in JDBC path", real);
        if (real instanceof Error) throw (Error) real; // do not swallow JVM errors
    }
    throw e;
}

Prevention

When it happens

Trigger: A user of DruidPooledConnection calls handleException(t) (or Druid invokes handleConnectionException) with a Throwable that is not a SQLException — e.g. a java.lang.Error (OutOfMemoryError, StackOverflowError), a RuntimeException from a custom Filter, or a driver bug throwing a raw RuntimeException. Line 1810 wraps it.

Common situations: A custom Filter/ConnectionProxy throwing a RuntimeException; driver bug surfacing as RuntimeException; OOM/StackOverflow during statement execution; third-party wrapper (e.g. P6Spy) throwing non-SQL exceptions; assertion errors in tests against a real connection.

Related errors


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