{"record":{"id":"cee25925125be784","repo":"biomejs/biome","slug":"could-not-find-any-pending-request-matching-rpc-re","errorCode":null,"errorMessage":"could not find any pending request matching RPC response ID ${body.id}","messagePattern":"could not find any pending request matching RPC response ID (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@biomejs/backend-jsonrpc/src/transport.ts","lineNumber":281,"sourceCode":"\t\t\t}\n\n\t\t\tif (isJsonRpcNotification(body)) {\n\t\t\t\t// TODO: Not implemented at the moment\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (isJsonRpcResponse(body)) {\n\t\t\t\tconst pendingRequest = this.pendingRequests.get(body.id);\n\t\t\t\tif (pendingRequest) {\n\t\t\t\t\tthis.pendingRequests.delete(body.id);\n\t\t\t\t\tconst { resolve, reject } = pendingRequest;\n\t\t\t\t\tif (\"result\" in body) {\n\t\t\t\t\t\tresolve(body.result);\n\t\t\t\t\t} else {\n\t\t\t\t\t\treject(body.error);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`could not find any pending request matching RPC response ID ${body.id}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tthrow new Error(\n\t\t\t`failed to deserialize incoming message from remote workspace, \"${data}\" is not a valid JSON-RPC message body`,\n\t\t);\n\t}\n}\n","sourceCodeStart":263,"sourceCodeEnd":294,"githubUrl":"https://github.com/biomejs/biome/blob/7529811358079edb5a2a9d4a5f67a9f639a63f3a/packages/@biomejs/backend-jsonrpc/src/transport.ts#L263-L294","documentation":"Each call to Transport.request() registers a resolver under an auto-incremented numeric id (nextRequestId, transport.ts:108, 130-141) in the pendingRequests map. When a JSON-RPC response arrives, its numeric id is looked up; if nothing is pending under that id the response can neither be delivered nor discarded safely, so the Transport throws (transport.ts:270-284). It means the peer sent a response the client never asked for, or asked for twice.","triggerScenarios":"The server sends a duplicate response for an id that was already resolved; the server invents its own ids that do not match the client's 0-based counter; a Transport instance is reused across a reconnect while nextRequestId was reset, so late responses from the old session reference unknown ids. Note an id that is a string instead of a number fails isJsonRpcResponse (transport.ts:72-81) and produces error [4] instead.","commonSituations":"Reconnect logic that keeps the old socket or Transport alive; a daemon bug double-answering one request; two clients multiplexed onto one socket; version skew between client and daemon.","solutions":["Create a fresh Transport (and a fresh socket) for every connection and destroy the old one on close, so stale responses can never arrive on the new instance.","Upgrade daemon and client packages to matching versions if a duplicate-response bug was fixed.","If you implement the server side of this protocol, always echo the request id exactly and respond exactly once per request.","Treat this error as fatal for the connection: destroy the Transport and reconnect, since the stream of pending requests is now inconsistent."],"exampleFix":"// before: one Transport shared across reconnects (id counter and pending map go stale)\nlet transport = new Transport(socket);\nfunction reconnect(newSocket) {\n\ttransport.destroy();\n\ttransport = new Transport(newSocket);\n}\n\n// after: fresh Transport per connection, destroyed with its socket\nfunction connect(socket) {\n\tconst transport = new Transport(socket);\n\tsocket.on(\"close\", () => transport.destroy());\n\treturn transport;\n}","handlingStrategy":"validation","validationCode":"// Keep Transport lifecycle 1:1 with the connection so pending ids can never go stale\nfunction connect(socket) {\n\tconst transport = new Transport(socket);\n\tsocket.on(\"close\", () => transport.destroy()); // no late responses on a dead socket\n\treturn transport;\n}","typeGuard":null,"tryCatchPattern":"// The throw happens while processing incoming data (not inside request()'s promise), so guard globally:\nprocess.on(\"uncaughtException\", (err) => {\n\tif (err.message.includes(\"could not find any pending request matching RPC response ID\")) {\n\t\t// Pending-request state is inconsistent; the safe recovery is a fresh connection.\n\t\ttransport.destroy();\n\t\treconnect();\n\t} else {\n\t\tthrow err;\n\t}\n});","preventionTips":["Never reuse a Transport instance across reconnects; its id counter and pending map belong to one connection.","Destroy the Transport whenever the underlying socket closes so late responses cannot be parsed.","If you implement the peer, always echo the request id exactly and respond at most once per request.","Run daemon and client packages from the same release so response-id behavior matches."],"tags":["jsonrpc","transport","request-id","rpc","connection-lifecycle"],"backgroundTag":"jsonrpc-unmatched-response-id","analyzedSha":"7529811358079edb5a2a9d4a5f67a9f639a63f3a","analyzedAt":"2026-08-16T22:13:27.842Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}