microsoft/typescript-go · error
unexpected message type: %d
Error message
unexpected message type: %d
What it means
ReadMessage parsed a valid tuple whose message type is one this reader never accepts from its peer: MessageTypeResponse, MessageTypeError, or MessageTypeCall. Only Request, CallResponse, and CallError are handled inbound; responses to this side's own Calls are consumed inline by SyncConn.Call, never by the main read loop.
Source
Thrown at internal/api/protocol_msgpack.go:90
msg.Method = method
msg.Params = payload
case MessageTypeCallResponse:
// Response to our Call - use method as ID
// Note: Method must be empty for IsResponse() to return true
id := jsonrpc.NewIDString(method)
msg.ID = id
msg.Result = payload
case MessageTypeCallError:
// Error response to our Call
// Note: Method must be empty for IsResponse() to return true
id := jsonrpc.NewIDString(method)
msg.ID = id
msg.Error = &jsonrpc.ResponseError{
Code: jsonrpc.CodeInternalError,
Message: string(payload),
}
default:
return nil, fmt.Errorf("unexpected message type: %d", msgType)
}
return msg, nil
}
func (p *MessagePackProtocol) readTuple() (MessageType, string, []byte, error) {
// Read fixed array marker (0x93 = 3-element array)
t, err := p.r.ReadByte()
if err != nil {
return 0, "", nil, err
}
if t != msgpackFixedArray3 {
return 0, "", nil, fmt.Errorf("%w: expected fixed 3-element array (0x93), received: 0x%02x", ErrInvalidRequest, t)
}
// Read message type - can be positive fixint (0x00-0x7F) or uint8 (0xCC + value)
t, err = p.r.ReadByte()
if err != nil {View on GitHub (pinned to 1bcfa18d79)
Solutions
- Verify exactly one side owns SyncConn.Run and answers requests, the other issues them
- Ensure the peer writes only request/call-response/call-error tuples toward this reader
- In loopback tests, route each side's writer to the OTHER side's reader
- Close and re-establish the connection after fixing wiring - the stream cannot be trusted
Example fix
// before go server.Run(ctx); go server.Run(ctx) // both reading same role frames // after go server.Run(ctx) // one side serves go clientLoop(ctx, clientConn) // other side calls
Defensive patterns
Strategy: try-catch
Try / catch
if err := conn.Run(ctx); err != nil {
if strings.Contains(err.Error(), "unexpected message type") {
// role wiring is wrong or the peer echoed our own frames; rebuild the link
return rebuildLinkWithCorrectRoles()
}
return err
} Prevention
- Exactly one side runs SyncConn.Run; the other issues Calls
- Route each side's writer to the other's reader in tests
- Never echo received frames back verbatim
When it happens
Trigger: Both ends of the pipe wired in the same role (two 'servers' or two 'clients'), so each writes Call/Response frames toward the other; a client echoing a server-written frame back; loopback tests piping a side's output to its own input.
Common situations: Constructing the two protocol endpoints with swapped roles; test harnesses connecting a writer to itself; debugging proxies that reflect frames.
Related errors
- %w: unknown message type: %d
- unknown callback name: %s
- api: unexpected message while waiting for %q response
- ErrInvalidRequest
- %w: expected fixed 3-element array (0x93), received: 0x%02x
AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16).
Data as JSON: /api/errors/6161c6aea9789aba.
Report an issue: GitHub.