github/copilot-sdk · error · InvalidDataException
JSON-RPC frame is missing the Content-Length header.
Error message
JSON-RPC frame is missing the Content-Length header.
What it means
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.
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.
Example fix
// before
await stream.WriteAsync(JsonBytes); // no header
// after
var json = Encoding.UTF8.GetBytes(payload);
var header = Encoding.ASCII.GetBytes($"Content-Length: {json.Length}\r\n\r\n");
await stream.WriteAsync(header); await stream.WriteAsync(json); Defensive patterns
Strategy: validation
Validate before calling
static byte[] Frame(byte[] json)
{
var header = Encoding.ASCII.GetBytes($"Content-Length: {json.Length}\r\n\r\n");
var frame = new byte[header.Length + json.Length];
header.CopyTo(frame, 0); json.CopyTo(frame, header.Length);
return frame;
} // use Frame() for every outgoing message Try / catch
try { await reader.ReadLoopAsync(ct); }
catch (InvalidDataException ex) when (ex.Message.Contains("missing the Content-Length")) {
logger.LogError(ex, "Peer omitted Content-Length; not a framed JSON-RPC peer");
transport.Close();
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- JSON-RPC frame has a missing, duplicate, or invalid…
- Stream ended while reading JSON-RPC headers.
- Client not started. Call start() first.
- Expected JSON object for `params` of single-object-param…
- Unexpected end of stream while reading JSON-RPC message
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/02a383c0f04dbb89.
Report an issue: GitHub.
Appendix: source
Thrown at dotnet/src/JsonRpc.cs:439
while (!headerLines.IsEmpty)
{
int lineEnd = headerLines.IndexOf("\r\n"u8);
ReadOnlySpan<byte> line = lineEnd >= 0 ? headerLines.Slice(0, lineEnd) : headerLines;
if (line.StartsWith(prefix) &&
(contentLength >= 0 ||
!int.TryParse(line.Slice(prefix.Length), NumberStyles.None, CultureInfo.InvariantCulture, out contentLength) ||
contentLength < 0))
{
throw new InvalidDataException("JSON-RPC frame has a missing, duplicate, or invalid Content-Length header.");
}
headerLines = lineEnd >= 0 ? headerLines.Slice(lineEnd + 2) : default;
}
if (contentLength < 0)
{
throw new InvalidDataException("JSON-RPC frame is missing the Content-Length header.");
}
// Bytes after the header that we already have
int extraBytes = filled - headerEnd;
// Ensure buffer is large enough for the body and any overflow already read.
int needed = Math.Max(contentLength, extraBytes);
if (needed > buffer.Length)
{
var newBuffer = new byte[needed];
Buffer.BlockCopy(buffer, headerEnd, newBuffer, 0, extraBytes);
buffer = newBuffer;
}
else if (extraBytes > 0)
{
Buffer.BlockCopy(buffer, headerEnd, buffer, 0, extraBytes);
}
View on GitHub (pinned to cd8cf15dc3)