microsoft/typescript-go · error · ErrInvalidRequest
%w: expected binary data (0xc4-0xc6), received: 0x%02x
Error message
%w: expected binary data (0xc4-0xc6), received: 0x%02x
What it means
The MessagePack protocol reader (MessagePackProtocol.readBin) expects the method and payload fields of every request tuple to be encoded as msgpack binary types bin8 (0xc4), bin16 (0xc5) or bin32 (0xc6), and it received a different type byte where binary data should start. This is a wire-framing violation: the server treats the incoming byte stream as desynchronized or incorrectly encoded and rejects the whole request wrapped in ErrInvalidRequest ("api: invalid request"). Note that most msgpack encoders serialize JS strings as str types (fixstr 0xa0-0xbf, str8 0xd9, str16 0xda), not bin, so naively encoding a string method name triggers exactly this error.
Source
Thrown at internal/api/protocol_msgpack.go:172
var size8 uint8
if err = binary.Read(p.r, binary.BigEndian, &size8); err != nil {
return nil, err
}
size = uint(size8)
case msgpackBin16:
var size16 uint16
if err = binary.Read(p.r, binary.BigEndian, &size16); err != nil {
return nil, err
}
size = uint(size16)
case msgpackBin32:
var size32 uint32
if err = binary.Read(p.r, binary.BigEndian, &size32); err != nil {
return nil, err
}
size = uint(size32)
default:
return nil, fmt.Errorf("%w: expected binary data (0xc4-0xc6), received: 0x%02x", ErrInvalidRequest, t)
}
payload := make([]byte, size)
if _, err := io.ReadFull(p.r, payload); err != nil {
return nil, err
}
return payload, nil
}
// WriteRequest implements Protocol.
func (p *MessagePackProtocol) WriteRequest(id *jsonrpc.ID, method string, params any) error {
// For msgpack protocol, requests from server are "Call" type
payload, err := json.Marshal(params)
if err != nil {
return err
}
return p.writeTuple(MessageTypeCall, method, payload)
}View on GitHub (pinned to 1bcfa18d79)
Solutions
- Encode both the method and the payload as msgpack bin: pass Uint8Array/Buffer values (e.g. Buffer.from(method, 'utf8') and Buffer.from(JSON.stringify(params))) so the encoder emits 0xc4-0xc6
- Verify the full frame layout: a fixed 3-element array 0x93 [messageType (fixint/uint8), method bin, payload bin]
- If a bad frame was already sent, tear down and re-establish the connection - the byte stream may be desynchronized and no retry on the same connection will recover
- If you meant to speak JSON-RPC, start the server with StdioServerOptions.Async = true (and JSONRPCProtocol) instead of msgpack
Example fix
// before (string encodes as msgpack str 0xa0-0xd9 -> error)
const frame = [msgType, "getSymbolAtPosition", JSON.stringify(params)];
write(msgpack.encode(frame));
// after (Uint8Array encodes as bin 0xc4-0xc6)
const frame = [msgType,
new TextEncoder().encode("getSymbolAtPosition"),
new TextEncoder().encode(JSON.stringify(params))];
write(msgpack.encode(frame)); // 0x93 <type> 0xc4.. 0xc4.. Defensive patterns
Strategy: validation
Validate before calling
// Before writing a frame, assert the method/payload fields will encode as msgpack bin.
function assertBinField(v: unknown, name: string): asserts v is Uint8Array {
if (!(v instanceof Uint8Array)) {
throw new TypeError(`${name} must be Uint8Array/Buffer so msgpack emits bin (0xc4-0xc6), got ${typeof v}`);
}
}
assertBinField(methodBytes, "method");
assertBinField(payloadBytes, "payload"); Type guard
const isBinEncodable = (v: unknown): v is Uint8Array => v instanceof Uint8Array || (typeof Buffer !== "undefined" && v instanceof Buffer);
Try / catch
try {
await conn.write(frame);
} catch (e) {
if (String(e).includes("api: invalid request") && String(e).includes("0xc4-0xc6")) {
// Stream framing is wrong/desynced; do NOT retry on this connection.
await conn.close();
throw new Error("msgpack framing error: encode method/payload as bin types", { cause: e });
}
throw e;
} Prevention
- Always wrap method and payload in TextEncoder().encode()/Buffer.from so the encoder emits bin, never str
- Use one well-tested frame-builder function for all requests instead of ad-hoc encodings
- Add a round-trip unit test: encode a request, decode it, assert the type bytes are 0x93/0xc4-0xc6
- Never mix protocols on one connection; msgpack mode is the default, JSON-RPC requires Async: true
When it happens
Trigger: Sending the method name or JSON payload as a msgpack string (str family) instead of bin; hand-rolling the frame and writing fixstr/array/nil bytes where the bin marker belongs; any earlier malformed frame that shifts the read offset so the next byte read as a bin marker is actually part of a previous value; using a different msgpack flavor (e.g. JSON-RPC text) on a connection the server opened with NewMessagePackProtocol (the sync, non-Async mode).
Common situations: A TypeScript client using @msgpack/msgpack, which encodes strings as str by default; porting a client from the JSON-RPC (Async: true) mode to the default msgpack mode and still sending text frames; a truncated write or partial flush that desyncs the stream; version skew between client encoder and server protocol expectations after upgrading typescript-go.
Related errors
- ErrInvalidRequest
- unexpected message type: %d
- %w: expected fixed 3-element array (0x93), received: 0x%02x
- %w: expected positive fixint or uint8 marker, received: 0x%0
- %w: unknown message type: %d
AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16).
Data as JSON: /api/errors/6cb6725d9f459d17.
Report an issue: GitHub.