{"record":{"id":"18d08ab80087d56d","repo":"redis/jedis","slug":"unexpected-end-of-stream","errorCode":null,"errorMessage":"Unexpected end of stream.","messagePattern":"Unexpected end of stream\\.","errorType":"exception","errorClass":"JedisConnectionException","httpStatus":null,"severity":"error","filePath":"src/main/java/redis/clients/jedis/util/RedisInputStream.java","lineNumber":259,"sourceCode":"    ensureFill();\n\n    final int length = Math.min(limit - count, len);\n    System.arraycopy(buf, count, b, off, length);\n    count += length;\n    return length;\n  }\n\n  /**\n   * This method assumes there are required bytes to be read. If we cannot read anymore bytes an\n   * exception is thrown to quickly ascertain that the stream was smaller than expected.\n   */\n  private void ensureFill() throws JedisConnectionException {\n    if (count >= limit) {\n      try {\n        limit = in.read(buf);\n        count = 0;\n        if (limit == -1) {\n          throw new JedisConnectionException(\"Unexpected end of stream.\");\n        }\n      } catch (IOException e) {\n        throw new JedisConnectionException(e);\n      }\n    }\n  }\n\n  @Override\n  public int available() throws IOException {\n    int availableInBuf = limit - count;\n    int availableInSocket = this.in.available();\n    return (availableInBuf > availableInSocket) ? availableInBuf : availableInSocket;\n  }\n\n}\n","sourceCodeStart":241,"sourceCodeEnd":275,"githubUrl":"https://github.com/redis/jedis/blob/6dac31d4c224fb3257c216f3985340c6f500cdcb/src/main/java/redis/clients/jedis/util/RedisInputStream.java#L241-L275","documentation":"ensureFill refills the internal buffer from the socket; when read() returns -1 the stream has reached EOF, meaning the server (or an intermediary) closed the TCP connection while Jedis still expected reply bytes. Jedis wraps this in JedisConnectionException(\"Unexpected end of stream.\").","triggerScenarios":"Thrown from ensureFill (used by peek, readByte, ensureCrLf, readLine, readLineBytes, readLineBytesSlowly) whenever more bytes are needed but the socket delivers EOF.","commonSituations":"Redis restarted or OOM-killed mid-command; server closed an idle connection (server `timeout`); LB/firewall silently dropping idle flows; command sent, then network drop before reply.","solutions":["Treat the connection as broken: close it and retry the command on a new connection.","Configure pool validation (testWhileIdle, evictor) so dead connections are not handed out.","Set socket timeout below server `timeout` and LB idle timeout; enable TCP keepalive.","Inspect Redis server logs for shutdowns, OOM, or client kills at the failure timestamp."],"exampleFix":"// before\nGenericObjectPoolConfig cfg = new GenericObjectPoolConfig();\ncfg.setTestOnBorrow(false);\n// after\nGenericObjectPoolConfig cfg = new GenericObjectPoolConfig();\ncfg.setTestWhileIdle(true);\ncfg.setTimeBetweenEvictionRunsMillis(30000);\ncfg.setMinEvictableIdleTimeMillis(60000);","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"RetryTemplate-style:\nfor (int attempt = 0; attempt < 2; attempt++) {\n  try (Jedis j = pool.getResource()) {\n    return j.get(key);\n  } catch (JedisConnectionException e) {\n    if (attempt == 1) throw e;\n    // else fall through and retry on a fresh connection\n  }\n}","preventionTips":["Configure pool eviction and validation to prune dead idle connections.","Align socket timeout with server `timeout` and infrastructure idle limits.","Monitor Redis restarts/OOM events; alert on server-side client kills.","Retry idempotent commands with backoff."],"tags":["connection","network","eof","redis"],"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"}