microsoft/typescript-go · error
api: unexpected message while waiting for %q response
Error message
api: unexpected message while waiting for %q response
What it means
SyncConn.Call read one message while waiting for the response to `method`, but it was not a response whose pseudo-ID matches. Because the msgpack protocol has no real request IDs, the method name doubles as the ID, so the reply must carry the identical method string and use a response message type. The awaited response is lost and the stream is desynchronized, so the call fails immediately.
Source
Thrown at internal/api/conn_sync.go:200
if ctx.Err() != nil {
return nil, ctx.Err()
}
// Read the response inline.
msg, err := c.protocol.ReadMessage()
if err != nil {
return nil, err
}
if msg.IsResponse() && msg.ID != nil && msg.ID.String() == method {
if msg.Error != nil {
return nil, fmt.Errorf("api: remote error [%d]: %s", msg.Error.Code, msg.Error.Message)
}
return msg.Result, nil
}
// Unexpected message while waiting for response
return nil, fmt.Errorf("api: unexpected message while waiting for %q response", method)
}
// Notify sends a notification to the client (no response expected).
func (c *SyncConn) Notify(ctx context.Context, method string, params any) error {
c.mu.Lock()
defer c.mu.Unlock()
return c.protocol.WriteNotification(method, params)
}
View on GitHub (pinned to 1bcfa18d79)
Solutions
- Make the client answer every server Call before writing anything else - the sync protocol requires strict turn-taking
- Verify the reply's method string matches the requested method byte-for-byte (case-sensitive)
- Ensure the peer writes MessageTypeCallResponse/MessageTypeCallError tuples when answering a Call
- Move long-running client work off the answering path so replies are never delayed past other writes
Example fix
// before (client loop): queues outgoing messages, then answers server calls
// after (client loop): answer server calls immediately, defer own messages
if msg.IsRequest() { reply(msg); continue } // nothing else written first Defensive patterns
Strategy: try-catch
Try / catch
res, err := conn.Call(ctx, method, params)
if err != nil && strings.Contains(err.Error(), "unexpected message while waiting") {
// stream is desynchronized; restart the connection, do not reuse it
return restartConn()
} Prevention
- Answer server Calls before writing any other message - strict turn-taking
- Echo the method string exactly as received when replying
- Reply with call-response/call-error tuples, never request/notification tuples
When it happens
Trigger: The client emits a request or notification before answering the server's Call; the client answers with a different method string (typo, case mismatch); the client replies with MessageTypeResponse instead of MessageTypeCallResponse/CallError so IsResponse() or the ID check fails.
Common situations: Client implementations that pipeline messages instead of strict turn-taking; method renames across versions; both sides calling simultaneously over one transport.
Related errors
- name mismatch for response: expected `${method}`, got `${thi
- unknown callback name: %s
- api: failed to write panic error response: %v (original pani
- api: failed to write response: %v
- api: remote error [%d]: %s
AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16).
Data as JSON: /api/errors/e44e2312f9d838de.
Report an issue: GitHub.