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
- Inspect getCause() of the thrown SQLException — it holds the real non-SQL Throwable; fix that root problem.
- If a custom Filter throws, have it wrap its failures in SQLException so they propagate cleanly instead of being re-wrapped as 'Error'.
- 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
- Make custom Filters throw SQLException, not RuntimeException, so they propagate cleanly.
- Never swallow the cause of a generic SQLException("Error") — it holds the real failure.
- Treat non-SQLException Throwables as serious; rethrow Errors.
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
- Error
- load managed jdbc driver event listener error. {filterName}
- validationQuery didn't return a row
- maxWaitThreadCount {}, current wait Thread count {}
- onFatalError, activeCount {}, onFatalErrorMaxActive {}
AI-assisted analysis of alibaba/druid@fa8dc99126 (2026-08-14).
Data as JSON: /api/errors/46b27ea0e448c8fc.
Report an issue: GitHub.