abhigyanpatwari/GitNexus · error · Error
Invalid Content-Length header from MCP client
Error message
Invalid Content-Length header from MCP client
What it means
Defensive validation in the stdio transport's frame parser: after the content-length regex captures a digit run, the value must parse to a finite, non-negative integer. Because the regex only captures \d+, ordinary malformed headers fail earlier as 'Missing Content-Length header'; this branch catches degenerate values such as a digit string so long that parseInt yields Infinity.
Source
Thrown at gitnexus/src/mcp/compatible-stdio-transport.ts:152
const header = findHeaderEnd(this._readBuffer);
if (header === null) {
return null;
}
const headerText = this._readBuffer
.toString('utf8', 0, header.index)
.replace(/\r\n/g, '\n')
.replace(/\r/g, '\n');
const match = headerText.match(/(?:^|\n)content-length\s*:\s*(\d+)/i);
if (!match) {
this.discardBufferedInput();
throw new Error('Missing Content-Length header from MCP client');
}
const contentLength = Number.parseInt(match[1], 10);
if (!Number.isFinite(contentLength) || contentLength < 0) {
this.discardBufferedInput();
throw new Error('Invalid Content-Length header from MCP client');
}
if (contentLength > MAX_BUFFER_SIZE) {
this.discardBufferedInput();
throw new Error(
`Content-Length ${contentLength} exceeds maximum allowed size (${MAX_BUFFER_SIZE} bytes)`,
);
}
const bodyStart = header.index + header.separatorLength;
const bodyEnd = bodyStart + contentLength;
if (this._readBuffer.length < bodyEnd) {
return null;
}
const body = this._readBuffer.toString('utf8', bodyStart, bodyEnd);
this._readBuffer = this._readBuffer.subarray(bodyEnd);
return deserializeMessage(body);
}
View on GitHub (pinned to aac7515d2a)
Solutions
- Fix the client to compute Content-Length from Buffer.byteLength of the serialized body and to validate Number.isFinite before writing.
- Replace hand-rolled framing with the official MCP SDK transport.
- Restart the session: the parser already discarded all buffered input, so the connection state is unrecoverable.
- If fuzzing/testing intentionally, feed well-formed frames instead.
Example fix
// before: length computed from a possibly non-finite value
const len = maybeCorruptedCounter;
sock.write(`Content-Length: ${len}\r\n\r\n` + body);
// after: derive from serialized bytes and validate before writing
const buf = Buffer.from(JSON.stringify(msg), 'utf8');
if (!Number.isFinite(buf.length) || buf.length < 0) throw new Error('bad length');
sock.write(`Content-Length: ${buf.length}\r\n\r\n`);
sock.write(buf); Defensive patterns
Strategy: validation
Validate before calling
// Validate a length before it ever reaches the wire
function frame(msg: unknown): Buffer {
const body = Buffer.from(JSON.stringify(msg), 'utf8');
const len = body.length;
if (!Number.isFinite(len) || len < 0 || !Number.isInteger(len)) {
throw new Error(`computed invalid Content-Length: ${len}`);
}
return Buffer.concat([Buffer.from(`Content-Length: ${len}\r\n\r\n`), body]);
} Try / catch
try {
await transport.handleData(chunk);
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
if (msg.includes('Invalid Content-Length')) {
// stream already discarded — treat the session as corrupt and restart it
await restartMcpSession();
return;
}
throw err;
} Prevention
- Derive Content-Length only from byte counts of the serialized payload.
- Assert Number.isFinite on any computed protocol field before writing it.
- Keep fuzz tests away from production transports, or feed only well-formed frames.
When it happens
Trigger: Corrupted or fuzzed stdin bytes that happen to form a header terminator plus a content-length line with an astronomically long digit run (overflowing Number to Infinity); a broken client or test harness computing the header value in a way that produces a non-representable number; memory-corrupted pipes writing garbage.
Common situations: Fuzzing the transport with random bytes; a client bug that stringifies NaN/Infinity into a length computation despite the digit-only regex; almost never seen with SDK-based clients — its appearance almost always indicates a broken hand-rolled client or corrupted stream.
Related errors
- Missing Content-Length header from MCP client
- Content-Length ${contentLength} exceeds maximum allowed size
- Refusing to start the MCP HTTP server on a non-loopback host
- list_repos: "${field}" must be an integer ${bound} (received
- No indexed repositories. Run: gitnexus analyze
AI-assisted analysis of abhigyanpatwari/GitNexus@aac7515d2a (2026-08-20).
Data as JSON: /api/errors/931a75d43a797acf.
Report an issue: GitHub.