apache/seatunnel · warning
Replaced an unusable pooled connection for queue index {}. {
Error message
Replaced an unusable pooled connection for queue index {}. {} replacement(s) since the last such message. Repeated messages indicate the connection is not surviving between writes. What it means
This is a throttled WARN from the JDBC sink's connection pool manager (ConnectionPoolManager.logReplacement). It fires when a pooled connection for a given queue index was found unusable (dead/stale) and had to be discarded and replaced. The message is rate-limited to once per REPLACEMENT_WARN_INTERVAL_NANOS and reports how many replacements occurred since the last warning; repeated warnings mean connections keep dying between writes rather than being a one-off stale connection.
Source
Thrown at seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/sink/ConnectionPoolManager.java:134
/**
* Reports a replaced connection at WARN, rate limited to one message per minute per manager.
*
* <p>Replacing an occasionally idle connection is the expected case and is not worth a warning
* on every occurrence. A validation that fails systematically is not: a misconfigured {@code
* connectionTestQuery}, a persistent network fault or a server-side connection limit makes
* every call replace the connection, which silently turns the cache off and churns connections
* continuously. Logging only at DEBUG would leave that indistinguishable from healthy operation
* in a default deployment, so the first occurrence and a periodic summary are surfaced.
*/
private void logReplacement(int index) {
long replacements = replacementsSinceLastWarn.incrementAndGet();
long now = System.nanoTime();
long last = lastReplacementWarnNanos.get();
if (now - last >= REPLACEMENT_WARN_INTERVAL_NANOS
&& lastReplacementWarnNanos.compareAndSet(last, now)) {
replacementsSinceLastWarn.addAndGet(-replacements);
log.warn(
"Replaced an unusable pooled connection for queue index {}. "
+ "{} replacement(s) since the last such message. Repeated messages "
+ "indicate the connection is not surviving between writes.",
index,
replacements);
return;
}
log.debug("Cached connection for queue index {} is no longer usable, replacing it", index);
}
private long getValidationTimeoutMillis() {
long configured = connectionPool.getValidationTimeout();
return configured > 0 ? configured : DEFAULT_VALIDATION_TIMEOUT_MILLIS;
}
private void closeQuietly(Connection connection) {View on GitHub (pinned to cf67b549a7)
Solutions
- Check DB server idle-connection kill settings (MySQL wait_timeout, PG idle_session_timeout) and set the pool's max idle/ maxLifetime below them
- Enable TCP keepalive and connection validation/test-on-borrow in the JDBC URL and pool config (e.g. connectTimeout, socketTimeout, keepalive properties)
- Reduce the interval between writes or configure the connector's connection pool keepalive so connections stay fresh
- Verify network middleboxes (LB/firewall/NAT) idle TCP timeouts and raise them or enable keepalives
- If only occasional, treat as benign — the pool already recovered; repeated warnings indicate a systematic idle-timeout mismatch
Example fix
// before: jdbc url without keepalive url=jdbc:mysql://db:3306/mydb // after url=jdbc:mysql://db:3306/mydb?connectTimeout=10000&socketTimeout=60000&tcpKeepAlive=true&autoReconnect=false
Defensive patterns
Strategy: validation
Validate before calling
// before submitting the job, probe and compare idle limits
try (Connection c = DriverManager.getConnection(url, user, pass)) {
if (c.isValid(5)) { System.out.println("connection ok, enable keepalive + pool test-on-borrow"); }
}
// keep pool maxIdleTime < DB wait_timeout (e.g. wait_timeout=600 -> maxIdleTime=300) Prevention
- Set pool maxLifetime/maxIdleTime below the DB server idle timeout
- Enable tcpKeepAlive and socketTimeout in the JDBC URL
- Prefer databases/middleboxes with long or disabled idle TCP timeouts
- Monitor this warn rate; a steady stream means a timeout mismatch, a rare one is benign
When it happens
Trigger: Calling getConnection when the pool hands out a connection that fails a validity/ usability check, so it is replaced. Happens repeatedly when the database or a network middlebox (firewall, LB, NAT) kills idle connections faster than they are reused, or when pool idle timeouts exceed server-side timeouts (e.g. MySQL wait_timeout, TCP keepalive off).
Common situations: Long idle periods between checkpointed write batches; cloud databases (RDS/Aurora/ProxySQL) dropping idle TCP connections; MySQL 'server has gone away'; PostgreSQL 'terminating connection due to administrator command'; misconfigured pool maxIdleTime larger than DB idle kill threshold.
Related errors
- Proxy Connection is null.
- JDBC connection close failed.
- JDBC connection close failed.
- The jdbc url format is incorrect: ${url}
- Failed to get connection, interrupted while doing another at
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/5dc529b561977429.
Report an issue: GitHub.