alibaba/druid · critical · DataSourceClosedException
dataSource already closed at {}
Error message
dataSource already closed at {} What it means
DataSourceClosedException (a SQLException subclass) thrown by getConnectionInternal when the datasource has been closed (closed == true). The message includes the close timestamp (closeTimeMillis) so callers can see when the pool was shut down. Once closed, the pool will not hand out connections and every getConnection fails fast.
Source
Thrown at core/src/main/java/com/alibaba/druid/pool/DruidDataSource.java:1553
discardCount++;
holder.discard = true;
int fillCount = minIdle - (activeCount + poolingCount + createTaskCount);
if (fillCount > 0) {
emptySignalCalled = true;
emptySignal(fillCount);
}
} finally {
lock.unlock();
}
return emptySignalCalled;
}
private DruidPooledConnection getConnectionInternal(long maxWait) throws SQLException {
if (closed) {
connectErrorCountUpdater.incrementAndGet(this);
throw new DataSourceClosedException("dataSource already closed at " + new Date(closeTimeMillis));
}
if (!enable) {
connectErrorCountUpdater.incrementAndGet(this);
if (disableException != null) {
throw disableException;
}
throw new DataSourceDisableException();
}
final int maxWaitThreadCount = this.maxWaitThreadCount;
DruidConnectionHolder holder;
long startTime = System.currentTimeMillis(); //进入循环等待之前,先记录开始尝试获取连接的时间
final long expiredTime = startTime + maxWait;View on GitHub (pinned to fa8dc99126)
Solutions
- Do not call getConnection() after close(); coordinate shutdown so callers stop before the pool closes.
- If the pool closed due to an error, inspect logs for the originating fatal condition and restart/recreate the datasource.
- Guard call sites: check dataSource.isClosed() (or isInited()) before borrowing, or wrap borrowing in a resilient client that recreates the pool.
- Ensure test/teardown ordering does not close the shared datasource while background threads are still using it.
Example fix
// before
public Connection borrow() throws SQLException {
return dataSource.getConnection(); // throws DataSourceClosedException after shutdown
}
// after
public Connection borrow() throws SQLException {
if (dataSource.isClosed()) {
throw new IllegalStateException("pool closed; recreate before use");
}
return dataSource.getConnection();
} Defensive patterns
Strategy: validation
Validate before calling
if (dataSource.isClosed()) {
throw new IllegalStateException("datasource closed at " + new Date(dataSource.getCloseTimeMillis())
+ "; recreate before borrowing");
}
Connection c = dataSource.getConnection(); Try / catch
try {
return dataSource.getConnection();
} catch (com.alibaba.druid.pool.DataSourceClosedException e) {
LOG.error("pool closed at {}; recreate datasource", new Date(dataSource.getCloseTimeMillis()));
throw new IllegalStateException("datasource closed; recreate required", e);
} Prevention
- Coordinate shutdown so callers stop borrowing before close().
- Guard call sites with isClosed() where reordering is possible.
- Investigate fatal errors that auto-close the pool and recreate it.
When it happens
Trigger: getConnection/getConnectionInternal is called after dataSource.close() ran (or after restart()/a fatal error closed it). The closed check at line 1551 throws, incrementing connectErrorCount.
Common situations: Application shutdown closing the datasource while request threads still call getConnection(); a health-check/fatal-error path that closed the pool; calling close() explicitly then reusing the bean; JUnit teardown ordering closing the pool before an async assertion runs.
Related errors
- dataSource already closed at {date}
- connect error, url {}, driverClass {}
- dataSource inited.
- check connection info failed
- can not restart, activeCount not zero. {}
AI-assisted analysis of alibaba/druid@fa8dc99126 (2026-08-14).
Data as JSON: /api/errors/035c83427465f44a.
Report an issue: GitHub.