{"record":{"id":"082060c178bba3d6","repo":"grpc/grpc-java","slug":"malformed-status-code","errorCode":null,"errorMessage":"Malformed status code ","messagePattern":"Malformed status code ","errorType":"exception","errorClass":"NumberFormatException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/io/grpc/internal/Http2ClientStreamTransportState.java","lineNumber":54,"sourceCode":"   */\n  private static final InternalMetadata.TrustedAsciiMarshaller<Integer> HTTP_STATUS_MARSHALLER =\n      new InternalMetadata.TrustedAsciiMarshaller<Integer>() {\n        @Override\n        public byte[] toAsciiString(Integer value) {\n          throw new UnsupportedOperationException();\n        }\n\n        /**\n         * RFC 7231 says status codes are 3 digits long.\n         *\n         * @see <a href=\"https://tools.ietf.org/html/rfc7231#section-6\">RFC 7231</a>\n         */\n        @Override\n        public Integer parseAsciiString(byte[] serialized) {\n          if (serialized.length >= 3) {\n            return (serialized[0] - '0') * 100 + (serialized[1] - '0') * 10 + (serialized[2] - '0');\n          }\n          throw new NumberFormatException(\n              \"Malformed status code \" + new String(serialized, InternalMetadata.US_ASCII));\n        }\n      };\n\n  private static final Metadata.Key<Integer> HTTP2_STATUS = InternalMetadata.keyOf(\":status\",\n      HTTP_STATUS_MARSHALLER);\n\n  /** When non-{@code null}, {@link #transportErrorMetadata} must also be non-{@code null}. */\n  private Status transportError;\n  private Metadata transportErrorMetadata;\n  private Charset errorCharset = StandardCharsets.UTF_8;\n  private boolean headersReceived;\n\n  protected Http2ClientStreamTransportState(\n      int maxMessageSize,\n      StatsTraceContext statsTraceCtx,\n      TransportTracer transportTracer,\n      CallOptions options) {","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/core/src/main/java/io/grpc/internal/Http2ClientStreamTransportState.java#L36-L72","documentation":"Http2ClientStreamTransportState defines a marshaller for the HTTP/2 ':status' pseudo-header that parses a 3-digit ASCII status code. parseAsciiString throws NumberFormatException('Malformed status code ...') when the byte array is shorter than 3 characters, i.e. the peer sent a status line that cannot be a valid HTTP status code.","triggerScenarios":"Receiving an HTTP/2 :status header whose serialized value has fewer than 3 bytes — a malformed frame from the peer, a broken proxy injecting a truncated status, or a test/bidi endpoint writing an invalid :status value.","commonSituations":"Misbehaving HTTP/2 proxies or load balancers; custom servers emitting non-conforming :status headers; fuzzing or corrupted transport frames; connecting gRPC to a non-gRPC HTTP/2 endpoint.","solutions":["Log the raw :status bytes and fix the peer/proxy that emits the malformed header","Ensure the server always sends a valid 3-digit :status (e.g. 200, 404) before closing the stream","Check for intermediaries that convert to HTTP/1.x and back, mangling the status","Upgrade the proxy/server software — this is a peer protocol violation"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// before accepting a peer's :status value\nif (statusBytes == null || statusBytes.length < 3) throw new IllegalArgumentException(\":status must be 3 ASCII digits\");","typeGuard":null,"tryCatchPattern":"try { transport.handleStatus(...); } catch (NumberFormatException e) {\n  if (e.getMessage().startsWith(\"Malformed status code\")) {\n    log.error(\"peer sent malformed :status: {}\", e.getMessage()); // fail the stream cleanly\n  } else throw e;\n}","preventionTips":["Test servers/proxies emit only RFC-valid 3-digit :status values","Fuzz HTTP/2 intermediaries before production","Upgrade proxies known to corrupt HTTP/2 pseudo-headers"],"tags":["grpc","http2","status-code","malformed-header"],"backgroundTag":"unexpected-http-status","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"}