{"record":{"id":"837098e94d6c37ea","repo":"grpc/grpc-java","slug":"eof-trying-to-read-length-bytes","errorCode":null,"errorMessage":"EOF trying to read ${length} bytes","messagePattern":"EOF trying to read (.+?) bytes","errorType":"exception","errorClass":"IndexOutOfBoundsException","httpStatus":null,"severity":"error","filePath":"okhttp/src/main/java/io/grpc/okhttp/OkHttpReadableBuffer.java","lineNumber":66,"sourceCode":"  }\n\n  private void fakeEofExceptionMethod() throws EOFException {}\n\n  @Override\n  public void skipBytes(int length) {\n    try {\n      buffer.skip(length);\n    } catch (EOFException e) {\n      throw new IndexOutOfBoundsException(e.getMessage());\n    }\n  }\n\n  @Override\n  public void readBytes(byte[] dest, int destOffset, int length) {\n    while (length > 0) {\n      int bytesRead = buffer.read(dest, destOffset, length);\n      if (bytesRead == -1) {\n        throw new IndexOutOfBoundsException(\"EOF trying to read \" + length + \" bytes\");\n      }\n      length -= bytesRead;\n      destOffset += bytesRead;\n    }\n  }\n\n  @Override\n  public void readBytes(OutputStream dest, int length) throws IOException {\n    buffer.writeTo(dest, length);\n  }\n\n  @Override\n  public ReadableBuffer readBytes(int length) {\n    okio.Buffer buf = new okio.Buffer();\n    buf.write(buffer, length);\n    return new OkHttpReadableBuffer(buf);\n  }\n","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/okhttp/src/main/java/io/grpc/okhttp/OkHttpReadableBuffer.java#L48-L84","documentation":"OkHttpReadableBuffer.readBytes throws IndexOutOfBoundsException 'EOF trying to read N bytes' when the underlying okio Buffer is exhausted before `length` bytes can be read. It indicates the received frame was truncated or the buffer accounting between HTTP/2 framing and the gRPC message buffer is wrong.","triggerScenarios":"Reading a serialized gRPC message from a transport buffer where fewer bytes arrived than the message header declared (truncated frame, stream reset mid-message, or corrupt length prefix).","commonSituations":"Network interruption cutting a DATA frame short, HTTP/2 flow-control or framing bugs, proxies that truncate long responses, mismatched message length fields from a faulty peer.","solutions":["Retry the RPC; a truncated frame usually means the stream failed mid-transfer","Check network path for proxies/load balancers that truncate large responses (raise proxy limits, disable buffering)","Upgrade grpc-okhttp / grpc-netty to rule out known framing bugs","Enable gRPC/okhttp logging and HTTP/2 frame traces to find where the truncation occurs"],"exampleFix":"// before\n// receiving side trusts message length; peer sends shorter frame -> EOF\n// after\n// enforce max inbound message size so oversized/corrupt lengths fail fast:\nOkHttpChannelBuilder.forAddress(host, port).maxInboundMessageSize(4 * 1024 * 1024).build();","handlingStrategy":"retry","validationCode":"// enforce sane inbound size before sending large messages\nif (msg.size() > maxInboundMessageSize) throw new IllegalArgumentException(\"message too large\");","typeGuard":null,"tryCatchPattern":"try { stub.unaryCall(req); } catch (StatusRuntimeException e) { if (e.getStatus().getCode() == Status.Code.INTERNAL || e.getStatus().getCode() == Status.Code.UNAVAILABLE) { retryWithBackoff(); } throw e; }","preventionTips":["Keep maxInboundMessageSize consistent on client and server","Avoid proxies that truncate large streamed bodies","Pin tested grpc-okhttp versions and watch for framing bugfixes"],"tags":["grpc","okhttp","framing","http2","truncated"],"backgroundTag":"unexpected-response-shape","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}