alibaba/druid · error · DataSourceClosedException

dataSource already closed at

Error message

dataSource already closed at {date}

What it means

Thrown by fill(int) (the API that pre-populates the pool with physical connections) when the DataSource is already closed. It is a DataSourceClosedException (SQLException subclass) and includes the timestamp at which close() was invoked, so you can tell when the pool was shut down.

Solutions

  1. Ensure fill() is called only after init() and before close(); move pre-warming into an init hook (Druid calls fill logic during init when configured).
  2. If the pool is closed, create a new DruidDataSource rather than calling fill() on the dead one.
  3. Coordinate shutdown so background fill/warm threads are stopped before the DataSource is closed.

Example fix

// before
@Scheduled(fixedDelay = 60_000)
void warm() { dataSource.fill(maxActive); } // fires after shutdown -> DataSourceClosedException

// after — stop the warmer before the pool closes
@PreDestroy
void shutdown() {
    warmScheduler.shutdownNow();
    dataSource.close();
}
Defensive patterns

Strategy: validation

Validate before calling

if (((DruidDataSource) dataSource).isClosed()) {
    throw new IllegalStateException("DataSource closed; cannot fill");
}
return dataSource.fill(toCount);

Try / catch

try {
    return dataSource.fill(toCount);
} catch (DataSourceClosedException e) {
    // pool is gone; either recreate it or skip warming
    log.warn("fill skipped, pool closed at {}", e.getMessage());
    return 0;
}

Prevention

When it happens

Trigger: dataSource.close() has run (closed == true) and then fill() or fill(toCount) is called. The guard at line 3813 throws DataSourceClosedException with new Date(closeTimeMillis).

Common situations: A warm-up/fill routine running on a timer that fires after Spring context shutdown; calling fill() in an @PreDestroy-adjacent phase; reusing a DataSource bean that was closed by a previous test; init/fill ordering mistake in a custom lifecycle.

Related errors


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

Appendix: source

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

        this.logDifferentThread = logDifferentThread;
    }

    public DruidPooledConnection tryGetConnection() throws SQLException {
        if (poolingCount == 0) {
            return null;
        }
        return getConnection();
    }

    @Override
    public int fill() throws SQLException {
        return this.fill(this.maxActive);
    }

    @Override
    public int fill(int toCount) throws SQLException {
        if (closed) {
            throw new DataSourceClosedException("dataSource already closed at " + new Date(closeTimeMillis));
        }

        if (toCount < 0) {
            throw new IllegalArgumentException("toCount can't not be less than zero");
        }

        init();

        if (toCount > this.maxActive) {
            toCount = this.maxActive;
        }

        int fillCount = 0;
        for (; ; ) {
            try {
                lock.lockInterruptibly();
            } catch (InterruptedException e) {
                connectErrorCountUpdater.incrementAndGet(this);

View on GitHub (pinned to fa8dc99126)