{"record":{"id":"6f486e48ab5c260d","repo":"redis/jedis","slug":"bulk-reply-length-is-less-than-expected","errorCode":null,"errorMessage":"Bulk reply length  is less than expected ","messagePattern":"Bulk reply length  is less than expected ","errorType":"exception","errorClass":"JedisConnectionException","httpStatus":null,"severity":"error","filePath":"src/main/java/redis/clients/jedis/Protocol.java","lineNumber":198,"sourceCode":"\n  private static byte[] processBulkReply(final RedisInputStream is) {\n    return processBulkReply(is, 0);\n  }\n\n  /**\n   * Process a bulk reply, optionally skipping a prefix.\n   * @param is the input stream\n   * @param skipBytes number of bytes to skip at the beginning (used for verbatim strings)\n   * @return the bulk reply data (excluding skipped bytes), or null if length is -1\n   */\n  private static byte[] processBulkReply(final RedisInputStream is, final int skipBytes) {\n    final int len = is.readIntCrLf();\n    if (len == -1) {\n      return null;\n    }\n\n    if (len < skipBytes) {\n      throw new JedisConnectionException(\n          \"Bulk reply length \" + len + \" is less than expected \" + skipBytes);\n    }\n\n    // Skip the prefix bytes\n    for (int i = 0; i < skipBytes; i++) {\n      is.readByte();\n    }\n\n    // Read the remaining data\n    final int dataLen = len - skipBytes;\n    final byte[] read = new byte[dataLen];\n    int offset = 0;\n    while (offset < dataLen) {\n      final int size = is.read(read, offset, (dataLen - offset));\n      if (size == -1) {\n        throw new JedisConnectionException(\"It seems like server has closed the connection.\");\n      }\n      offset += size;","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/redis/jedis/blob/6dac31d4c224fb3257c216f3985340c6f500cdcb/src/main/java/redis/clients/jedis/Protocol.java#L180-L216","documentation":"processBulkReply reads the declared bulk-string length; when a fixed prefix (skipBytes, e.g. verbatim-string prefix) must be skipped but the declared length is smaller than that prefix, the reply is malformed and JedisConnectionException is thrown. This indicates a protocol violation from the server.","triggerScenarios":"Receiving a bulk reply whose length header is smaller than the required prefix — practically only via processVerbatimStringReply (RESP3 verbatim strings, like from LOLWUT) where the server claims a length under 4.","commonSituations":"Non-conforming server implementations, corrupted network stream desync causing a length misread, or unusual RESP3-emitting proxies.","solutions":["Reset the connection; desynced streams corrupt subsequent length parsing.","Verify the server is a genuine Redis instance supporting RESP3 verbatim strings.","Capture the raw reply (tcpdump/wireshark or MONITOR) to inspect the malformed response.","Upgrade Jedis and the server to aligned versions."],"exampleFix":"// before (desynced shared connection)\nConnection conn = sharedConnection; // used by two threads\nconn.sendCommand(VERBATIM_CMD);\n\n// after\ntry (Connection conn = pool.getResource()) { // dedicated connection per operation\n  conn.sendCommand(VERBATIM_CMD);\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  return connection.executeCommand(cmd);\n} catch (JedisConnectionException e) {\n  connection.close(); // discard possibly desynced connection\n  return retryOnFreshConnection(cmd);\n}","preventionTips":["Discard (never reuse) connections after protocol exceptions to avoid desync.","Use pooled connections so a corrupt connection is replaced automatically.","Run standard Redis servers and keep client/server versions aligned.","Investigate malformed replies with packet capture if reproducible."],"tags":["protocol","resp3","malformed-response","connection"],"backgroundTag":"unexpected-response-shape","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"}