This error occurs when the Jedis Java client loses connection to Redis, usually due to idle timeout, network issues, or stale connection pool entries. The server closes the connection, but the client attempts to use it anyway.
A "broken pipe" error indicates that the TCP connection between your Java application and Redis server has been terminated unexpectedly. When you try to read from or write to a closed connection, the operating system throws this error because the pipe (communication channel) is no longer valid. This typically happens in two scenarios: 1. **Server-side closure**: Redis closes an idle connection after the configured timeout period, but your client tries to reuse it. 2. **Network disruption**: The connection is interrupted by network issues, firewall rules, or server shutdown, but the client's connection pool still holds a stale reference. The Jedis library (Java Redis client) manages connections through a connection pool, and broken pipe errors indicate that a pooled connection is no longer usable.
Configure Jedis to validate connections before reusing them from the pool. This ensures stale connections are detected and discarded:
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setTestOnBorrow(true); // Validate when borrowing from pool
poolConfig.setTestOnReturn(true); // Validate when returning to pool
poolConfig.setTestWhileIdle(true); // Validate idle connections
poolConfig.setMinEvictableIdleTimeMillis(300000); // Remove connections idle > 5 min
poolConfig.setTimeBetweenEvictionRunsMillis(30000); // Check every 30 seconds
JedisPool pool = new JedisPool(poolConfig, "localhost", 6379);This prevents reuse of connections that Redis has already closed.
Configure connection and socket timeouts to balance responsiveness with reliability:
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxWaitMillis(3000); // Wait max 3 seconds for available connection
// Connection timeout and socket timeout in milliseconds
int timeout = 5000; // 5 seconds - must be less than Redis server timeout
JedisPool pool = new JedisPool(poolConfig, "localhost", 6379, timeout);Ensure your timeout is significantly less than Redis's timeout setting to prevent server-side closure while operations are pending.
Check your Redis server configuration and adjust the idle connection timeout:
# Connect to Redis and check current timeout
redis-cli CONFIG GET timeout
# Output: 1) "timeout"
# 2) "0" (0 means disabled - connections never close due to idle)If you see a timeout value (typically 300 seconds), consider:
- Setting timeout 0 to disable server-side timeout (if you have validation enabled)
- Or increasing it to a larger value if you prefer server-side cleanup
- Ensure your Jedis pool validation detects closed connections
# In redis.conf or via CLI (persistent requires redis.conf update)
CONFIG SET timeout 0Always use try-with-resources or explicit resource cleanup:
// Best practice: try-with-resources
try (Jedis jedis = pool.getResource()) {
String value = jedis.get("key");
jedis.set("key", "value");
} // Connection automatically returned to pool
// Alternative: explicit close
Jedis jedis = pool.getResource();
try {
jedis.set("key", "value");
} finally {
jedis.close(); // Returns connection to pool
}Never hold connections beyond their use scope, as this prevents timely reuse and increases likelihood of timeout.
Implement resilience for transient connection failures:
public static <T> T executeWithRetry(Supplier<T> operation) {
int maxRetries = 3;
long delayMs = 100;
for (int attempt = 1; attempt <= maxRetries; attempt++) {
try {
return operation.get();
} catch (JedisConnectionException e) {
if (attempt == maxRetries) {
throw e;
}
try {
Thread.sleep(delayMs);
delayMs *= 2; // Exponential backoff
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
throw new RuntimeException(ie);
}
}
}
throw new RuntimeException("Max retries exceeded");
}
// Usage
String value = executeWithRetry(() -> jedis.get("key"));Keep Jedis up to date and monitor pool health:
<!-- Update to latest stable version in pom.xml -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>5.1.0</version>
</dependency>Monitor connection pool metrics to catch issues early:
if (pool instanceof JedisPool) {
int active = pool.getNumActive();
int idle = pool.getNumIdle();
System.out.println("Active: " + active + ", Idle: " + idle);
}High idle counts with frequent broken pipe errors suggest your timeout is too aggressive.
Connection Pool Eviction: Jedis uses Apache Commons Pool2, which can evict idle connections. The minEvictableIdleTimeMillis and timeBetweenEvictionRunsMillis settings control this behavior. Set these to values less than your Redis server timeout to proactively clean up stale connections before they cause errors.
keepalive vs timeout: Redis's tcp-keepalive setting (default 300 seconds) keeps TCP connections alive at the OS level, while timeout closes idle connections at the Redis application level. These work independently—keepalive prevents TCP-level disconnection, but doesn't prevent Redis from closing the connection.
Cluster Mode: If using Redis Cluster with Jedis, ensure all nodes have consistent timeout configurations and that your client's pool settings account for node-level failures.
Monitoring: Use Redis CLIENT LIST to see active connections and their idle times:
redis-cli CLIENT LIST
# Look for 'idle' column—if close to your timeout, broken pipe errors will followERR fsync error
How to fix "ERR fsync error" in Redis
CLUSTERDOWN The cluster is down
How to fix 'CLUSTERDOWN The cluster is down' in Redis
ERR Job for redis-server.service failed because a timeout was exceeded
Job for redis-server.service failed because a timeout was exceeded
ERR Unbalanced XREAD list of streams
How to fix "ERR Unbalanced XREAD list" in Redis
ERR syntax error
How to fix "ERR syntax error" in Redis