biomejs/biome · error · Error
incoming message from the remote workspace is missing the Co
Error message
incoming message from the remote workspace is missing the Content-Length header
What it means
The Transport class in @biomejs/backend-jsonrpc speaks the LSP-style JSON-RPC wire protocol over a socket: each message is preceded by a header block terminated by a blank \r\n line, and Content-Length tells the reader how many body bytes follow (transport.ts:209-224). When the blank line arrives but the reader state never recorded a Content-Length value (typeof contentLength !== "number"), the framer has no way to know the body size and throws this error. In practice it means the bytes on the socket are not framed the way this Transport expects.
Source
Thrown at packages/@biomejs/backend-jsonrpc/src/transport.ts:213
this.pendingData = this.pendingData.subarray(
this.readerState.contentLength,
);
this.processIncomingBody(body);
this.readerState = {
kind: ReaderStateKind.Header,
};
} else {
break;
}
}
}
private processIncomingHeader(readerState: ReaderStateHeader, line: string) {
if (line === "\r\n") {
const { contentLength, contentType } = readerState;
if (typeof contentLength !== "number") {
throw new Error(
"incoming message from the remote workspace is missing the Content-Length header",
);
}
this.readerState = {
kind: ReaderStateKind.Body,
contentLength,
contentType,
};
return;
}
const colonIndex = line.indexOf(":");
if (colonIndex < 0) {
throw new Error(`could not find colon token in "${line}"`);
}
const headerName = line.substring(0, colonIndex);View on GitHub (pinned to 7529811358)
Solutions
- Verify the socket is connected to the actual Biome daemon (correct host/port/socket path), not to an HTTP endpoint or other service.
- Log raw chunks on the socket and confirm every message is framed as 'Content-Length: <n>\r\nContent-Type: application/vscode-jsonrpc;charset=utf-8\r\n\r\n<json body>' exactly like sendMessage does (transport.ts:164-170).
- Align versions: use a @biomejs/backend-jsonrpc (or @biomejs/js-api / daemon client) whose protocol matches the running daemon.
- If you implement the peer yourself, always write a Content-Length header whose value is the byte length of the body before writing the body.
Example fix
// before: peer writes the JSON body with no headers
socket.write(Buffer.from(JSON.stringify(message)));
// after: peer frames the message like Transport.sendMessage does
const body = Buffer.from(JSON.stringify(message));
const headers = Buffer.from(
`Content-Length: ${body.length}\r\nContent-Type: application/vscode-jsonrpc;charset=utf-8\r\n\r\n`,
);
socket.write(Buffer.concat([headers, body])); Defensive patterns
Strategy: validation
Validate before calling
// Peek at the first chunk BEFORE constructing Transport, to verify the peer speaks the header framing
function assertPeerFraming(socket) {
return new Promise((resolve, reject) => {
socket.once("data", (chunk) => {
const head = chunk.toString("utf-8", 0, 128);
if (/^Content-Length:\s*\d+/i.test(head)) {
resolve(socket);
} else {
socket.destroy();
reject(new Error(`peer does not speak the JSON-RPC framing protocol, got: ${JSON.stringify(head)}`));
}
});
});
} Try / catch
// The throw happens inside the socket 'data' handler, so it surfaces as an uncaught exception.
// Catch it there and fail the connection instead of the process:
process.on("uncaughtException", (err) => {
if (err.message.includes("missing the Content-Length header")) {
transport.destroy();
reconnect();
} else {
throw err;
}
}); Prevention
- Pin @biomejs/backend-jsonrpc (or the js-api client) and the daemon to matching versions so framing never changes under you.
- Never point the Transport at an unverified port/socket; probe the first bytes for 'Content-Length:' before wiring it up.
- If you implement the peer, frame exactly like sendMessage: Content-Length from the Buffer byte length, CRLF line endings, vscode-jsonrpc content type.
- Add an integration test that round-trips one request/response through the socket to catch framing regressions early.
When it happens
Trigger: The peer writes a header block ending in \r\n without a Content-Length header; the socket is connected to a process that is not the Biome daemon (HTTP server, raw JSON stream, REPL banner); or an earlier framing desync causes arbitrary bytes to be interpreted as a header block. Triggered from processIncomingHeader, reached via the socket 'data' handler registered in the Transport constructor (transport.ts:117-119).
Common situations: Pointing the Transport at the wrong port or socket path; a version mismatch where the daemon's wire format changed; a proxy or wrapper injecting bytes into the stream; a custom mock daemon in tests that writes JSON bodies without headers.
Related errors
- could not find colon token in "${line}"
- invalid value for Content-Type expected "${MIME_JSONRPC}", g
- failed to deserialize incoming message from remote workspace
- could not find any pending request matching RPC response ID
- Failed to parse URI {}: {e}
AI-assisted analysis of biomejs/biome@7529811358 (2026-08-16).
Data as JSON: /api/errors/c845022926f3ddc5.
Report an issue: GitHub.