github/copilot-sdk · error
Copilot request response used after RPC connection closed.
Error message
Copilot request response used after RPC connection closed.
What it means
Responses are delivered to the runtime via an RPC connection obtained through #rpc(). If that connection has closed (or was never available), the handler cannot forward httpResponseStart/Chunk calls. #rpc() throws this error whenever the server RPC accessor returns nothing.
Solutions
- Check connection state before starting response emission and skip/abort the response if the RPC connection is down.
- Keep handler processing short so the response is emitted within the connection's lifetime.
- Wrap the whole emit sequence in try/catch and treat this as an unrecoverable transport failure — log and return.
- Investigate why the RPC connection closed (runtime exit, timeout, network) if this occurs routinely.
- Enable reconnect/keepalive at the client/runtime layer if supported by your setup.
Example fix
// before
await longCompute();
await handler.startResponse({ status: 200 }); // may throw if RPC closed
// after
if (!handler.rpcConnected) return; // skip emission when transport is gone
await longCompute();
await handler.startResponse({ status: 200 }); Defensive patterns
Strategy: try-catch
Validate before calling
function isRpcClosed(e: unknown): boolean {
return e instanceof Error && e.message.includes('used after RPC connection closed');
}
// check before emitting
if (typeof handler.rpcConnected === 'boolean' && !handler.rpcConnected) return; Try / catch
try {
await handler.startResponse({ status: 200 });
await handler.writeResponse(body);
await handler.endResponse();
} catch (e) {
if (isRpcClosed(e)) { log.warn('response dropped: RPC connection closed'); return; }
throw e;
} Prevention
- Emit responses promptly; avoid long compute between request and response.
- Wrap the entire emit sequence so partial responses don't leave dangling state.
- Monitor RPC connection health/lifetime for long-running handlers.
- Investigate recurring connection drops (timeouts, restarts, network).
When it happens
Trigger: The WebSocket/RPC connection to the Copilot runtime closes while the handler is still emitting the response — calling startResponse, writeResponse, endResponse, or errorResponse afterwards.
Common situations: Long-running handlers that outlive the connection (runtime restart, network drop, client process exit); slow work followed by response emission after the session ended.
Understand the failure class
Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.
- Connection failures: ECONNREFUSED, ECONNRESET, and friends — why connections get refused, reset, or dropped.
Related errors
- Copilot request response used after RPC connection closed.
- failed to create session
- failed to resume session
- failed to send message
- failed to get events
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/7035ed968775375e.
Report an issue: GitHub.
Appendix: source
Thrown at nodejs/src/copilotRequestHandler.ts:640
}
async errorResponse(error: { message: string; code?: string }): Promise<void> {
if (this.#finished) {
return;
}
this.#finished = true;
await this.#rpc().llmInference.httpResponseChunk({
requestId: this.requestId,
data: "",
end: true,
error: { message: error.message, code: error.code },
});
}
#rpc(): ServerRpc {
const r = this.#getServerRpc();
if (!r) {
throw new Error("Copilot request response used after RPC connection closed.");
}
return r;
}
}
const FORBIDDEN_REQUEST_HEADERS = new Set([
"host",
"connection",
"content-length",
"transfer-encoding",
"keep-alive",
"upgrade",
"proxy-connection",
"te",
"trailer",
]);
async function buildFetchRequest(exchange: CopilotRequestExchange): Promise<Request> {View on GitHub (pinned to cd8cf15dc3)