{"record":{"id":"f556f190e92ac30f","repo":"redis/jedis","slug":"attempting-to-read-from-a-broken-connection","errorCode":null,"errorMessage":"Attempting to read from a broken connection.","messagePattern":"Attempting to read from a broken connection\\.","errorType":"exception","errorClass":"JedisConnectionException","httpStatus":null,"severity":"critical","filePath":"src/main/java/redis/clients/jedis/Connection.java","lineNumber":781,"sourceCode":"    } catch (IOException ex) {\n      throw markBroken(new JedisConnectionException(ex));\n    } catch (Error err) {\n      throw markBroken(err);\n    }\n  }\n\n  @Experimental\n  protected Object protocolRead(RedisInputStream is, PushConsumerChain consumer) {\n    return Protocol.read(is, consumer);\n  }\n\n  @Experimental\n  protected void protocolReadPushes(RedisInputStream is, PushConsumerChain consumer) {\n  }\n\n  protected Object readProtocolWithCheckingBroken() {\n    if (broken) {\n      throw new JedisConnectionException(\"Attempting to read from a broken connection.\", brokenCause);\n    }\n    try {\n      applyCurrentTimeout();\n      return protocolRead(inputStream, pushConsumers);\n    } catch (JedisDataException exc) {\n      // Redis error reply was fully parsed; the stream is aligned and the connection reusable.\n      throw exc;\n    } catch (RuntimeException exc) {\n      // Transport failures (JedisConnectionException) and any other unexpected failure mid-read\n      // leave the stream position indeterminate.\n      throw markBroken(exc);\n    } catch (Error err) {\n      throw markBroken(err);\n    }\n  }\n\n  protected void readPushesWithCheckingBroken() {\n    if (broken) {","sourceCodeStart":763,"sourceCodeEnd":799,"githubUrl":"https://github.com/redis/jedis/blob/6dac31d4c224fb3257c216f3985340c6f500cdcb/src/main/java/redis/clients/jedis/Connection.java#L763-L799","documentation":"readProtocolWithCheckingBroken() refuses to read a reply from a connection previously marked broken, throwing JedisConnectionException with the stored brokenCause. Reading from a broken connection could desynchronize the protocol stream.","triggerScenarios":"Calling getOne/readProtocol paths after an earlier write or read failure marked the connection broken; awaiting a reply for a command that was never (or only partially) written.","commonSituations":"Half-completed command round-trips after socket timeout; pub/sub or pipeline consumers reading after a network drop; connection reused across threads after one thread hit an error.","solutions":["Close/invalidate the connection and obtain a fresh one, then resend the command if idempotent","Catch JedisConnectionException and treat the in-flight command as failed (no reliable reply)","Check brokenCause to identify the initial failure (timeout, reset, closed socket)","Avoid sharing a Connection across threads so errors are not interleaved"],"exampleFix":"// before\nObject reply = connection.readProtocolCheckingBroken(); // broken\n// after\ntry {\n  Object reply = connection.readProtocolCheckingBroken();\n} catch (JedisConnectionException e) {\n  pool.returnBrokenResource(resource);\n  resource = pool.getResource(); // retry command on new connection\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { reply = conn.readProtocolCheckingBroken(); } catch (JedisConnectionException e) { invalidate(conn); throw new CommandFailedException(cmd, e); }","preventionTips":["Never share a Connection across threads","Treat in-flight commands as failed after this error; resend on a fresh connection","Set sane socket timeouts to avoid silent half-writes","Prefer higher-level clients (UnifiedJedis) that handle broken connections"],"tags":["jedis","connection","network","read"],"backgroundTag":"broken-pipe","analyzedSha":"6dac31d4c224fb3257c216f3985340c6f500cdcb","analyzedAt":"2026-09-08T04:55:01.204Z","contentChangedAt":"2026-09-08T04:55:01.204Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}