{"record":{"id":"02a383c0f04dbb89","repo":"github/copilot-sdk","slug":"json-rpc-frame-is-missing-the-content-length-heade","errorCode":null,"errorMessage":"JSON-RPC frame is missing the Content-Length header.","messagePattern":"JSON-RPC frame is missing the Content-Length header\\.","errorType":"exception","errorClass":"InvalidDataException","httpStatus":null,"severity":"error","filePath":"dotnet/src/JsonRpc.cs","lineNumber":439,"sourceCode":"        while (!headerLines.IsEmpty)\n        {\n            int lineEnd = headerLines.IndexOf(\"\\r\\n\"u8);\n            ReadOnlySpan<byte> line = lineEnd >= 0 ? headerLines.Slice(0, lineEnd) : headerLines;\n\n            if (line.StartsWith(prefix) &&\n                (contentLength >= 0 ||\n                 !int.TryParse(line.Slice(prefix.Length), NumberStyles.None, CultureInfo.InvariantCulture, out contentLength) ||\n                 contentLength < 0))\n            {\n                throw new InvalidDataException(\"JSON-RPC frame has a missing, duplicate, or invalid Content-Length header.\");\n            }\n\n            headerLines = lineEnd >= 0 ? headerLines.Slice(lineEnd + 2) : default;\n        }\n\n        if (contentLength < 0)\n        {\n            throw new InvalidDataException(\"JSON-RPC frame is missing the Content-Length header.\");\n        }\n\n        // Bytes after the header that we already have\n        int extraBytes = filled - headerEnd;\n\n        // Ensure buffer is large enough for the body and any overflow already read.\n        int needed = Math.Max(contentLength, extraBytes);\n        if (needed > buffer.Length)\n        {\n            var newBuffer = new byte[needed];\n            Buffer.BlockCopy(buffer, headerEnd, newBuffer, 0, extraBytes);\n            buffer = newBuffer;\n        }\n        else if (extraBytes > 0)\n        {\n            Buffer.BlockCopy(buffer, headerEnd, buffer, 0, extraBytes);\n        }\n","sourceCodeStart":421,"sourceCodeEnd":457,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/dotnet/src/JsonRpc.cs#L421-L457","documentation":"After scanning all header lines, if no Content-Length header was seen (contentLength still -1), ReadMessageAsync throws InvalidDataException: the frame simply omitted the mandatory Content-Length header, so the body size is unknowable.","triggerScenarios":"Peer writes only e.g. \"Content-Type: ...\" or a bare \"\\r\\n\" delimiter with no Content-Length line; newline-only ping frames; a sender that forgot to include the header entirely.","commonSituations":"Implementations of the LSP/JSON-RPC wire protocol that assume newline-delimited JSON instead of header-framed messages; sending raw JSON without the Content-Length wrapper.","solutions":["Always prefix each message with \"Content-Length: <byteCount>\\r\\n\\r\\n\" before the JSON body.","Compute Content-Length from the UTF-8 byte length of the payload, not the character count.","If you need newline-delimited JSON, use a transport mode that supports it instead of the framed reader.","Test the sender against a header-framed reference implementation."],"exampleFix":"// before\nawait stream.WriteAsync(JsonBytes); // no header\n// after\nvar json = Encoding.UTF8.GetBytes(payload);\nvar header = Encoding.ASCII.GetBytes($\"Content-Length: {json.Length}\\r\\n\\r\\n\");\nawait stream.WriteAsync(header); await stream.WriteAsync(json);","handlingStrategy":"validation","validationCode":"static byte[] Frame(byte[] json)\n{\n    var header = Encoding.ASCII.GetBytes($\"Content-Length: {json.Length}\\r\\n\\r\\n\");\n    var frame = new byte[header.Length + json.Length];\n    header.CopyTo(frame, 0); json.CopyTo(frame, header.Length);\n    return frame;\n} // use Frame() for every outgoing message","typeGuard":null,"tryCatchPattern":"try { await reader.ReadLoopAsync(ct); }\ncatch (InvalidDataException ex) when (ex.Message.Contains(\"missing the Content-Length\")) {\n    logger.LogError(ex, \"Peer omitted Content-Length; not a framed JSON-RPC peer\");\n    transport.Close();\n}","preventionTips":["Always emit Content-Length from UTF-8 byte length","Use newline-delimited transports only when both ends support them","Lint client framing code against protocol conformance tests","Reject unframed sends at the sender's serialization layer"],"tags":["jsonrpc","framing","missing-header"],"backgroundTag":"missing-required-argument","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}