biomejs/biome · error · Error

invalid value for Content-Type expected "${MIME_JSONRPC}", g

Error message

invalid value for Content-Type expected "${MIME_JSONRPC}", got "${headerValue}"

What it means

The framer accepts an optional Content-Type header, but if present its value must start with the constant MIME_JSONRPC = "application/vscode-jsonrpc" (transport.ts:99, 240-245). Any other Content-Type aborts parsing immediately, because the peer is demonstrably not speaking the expected JSON-RPC dialect.

Source

Thrown at packages/@biomejs/backend-jsonrpc/src/transport.ts:242

		}

		const colonIndex = line.indexOf(":");
		if (colonIndex < 0) {
			throw new Error(`could not find colon token in "${line}"`);
		}

		const headerName = line.substring(0, colonIndex);
		const headerValue = line.substring(colonIndex + 1).trim();

		switch (headerName) {
			case "Content-Length": {
				const value = Number.parseInt(headerValue, 10);
				readerState.contentLength = value;
				break;
			}
			case "Content-Type": {
				if (!headerValue.startsWith(MIME_JSONRPC)) {
					throw new Error(
						`invalid value for Content-Type expected "${MIME_JSONRPC}", got "${headerValue}"`,
					);
				}

				readerState.contentType = headerValue;
				break;
			}
			default:
				console.warn(`ignoring unknown header "${headerName}"`);
		}
	}

	private processIncomingBody(buffer: Buffer) {
		const data = buffer.toString("utf-8");
		const body = JSON.parse(data);

		if (isJsonRpcMessage(body)) {
			if (isJsonRpcRequest(body)) {

View on GitHub (pinned to 7529811358)

Solutions

  1. Confirm the socket endpoint belongs to the Biome daemon and that no HTTP proxy sits in between.
  2. If you implement the peer, send exactly 'Content-Type: application/vscode-jsonrpc;charset=utf-8' as sendMessage does (transport.ts:167) or omit the Content-Type header entirely (it is optional).
  3. Capture the first bytes of the stream and compare them against the expected header block to identify what is actually answering.

Example fix

// before: peer sends a generic content type
socket.write(`Content-Length: ${body.length}\r\nContent-Type: application/json\r\n\r\n`);

// after: peer sends the expected vscode-jsonrpc content type
socket.write(`Content-Length: ${body.length}\r\nContent-Type: application/vscode-jsonrpc;charset=utf-8\r\n\r\n`);
Defensive patterns

Strategy: validation

Validate before calling

// Peek the Content-Type line before handing the socket to Transport
socket.once("data", (chunk) => {
	const text = chunk.toString("utf-8", 0, 512);
	const m = text.match(/^Content-Type:\s*(.+?)\r?$/m);
	if (m && !m[1].startsWith("application/vscode-jsonrpc")) {
		socket.destroy();
		throw new Error(`unexpected peer Content-Type: ${m[1]}`);
	}
});

Try / catch

process.on("uncaughtException", (err) => {
	if (err.message.includes("invalid value for Content-Type")) {
		// The endpoint is not a vscode-jsonrpc peer; do not retry the same address.
		transport.destroy();
		throw new Error("connected to a non-JSON-RPC endpoint; check host/port");
	} else {
		throw err;
	}
});

Prevention

When it happens

Trigger: The peer replies with 'Content-Type: application/json', 'text/html', or similar; typically an HTTP server, proxy error page, or custom implementation answering on the socket instead of the Biome daemon. The startsWith check also rejects truncated or rewritten values injected by intermediaries.

Common situations: An HTTP/JSON service or reverse proxy answering on the port the Transport is connected to; a mock daemon in tests that sets a generic application/json content type; middleware that rewrites header values.

Related errors


AI-assisted analysis of biomejs/biome@7529811358 (2026-08-16). Data as JSON: /api/errors/6197353712713512. Report an issue: GitHub.