github/copilot-sdk · warning

Copilot request was cancelled by the runtime.

Error message

Copilot request was cancelled by the runtime.

What it means

When the runtime cancels the request, the handler marks itself cancelled and further response writes would target a request the runtime no longer reads. writeResponse() checks the cancelled flag and throws before sending an httpResponseChunk over the RPC channel.

Solutions

  1. Catch this error in the streaming loop, stop generating, and clean up — it means the peer is gone.
  2. Check the handler's cancellation state before each write and break out of the loop early.
  3. Suppress this error as a normal abort rather than logging it as a failure.
  4. Reduce per-chunk work so cancellation between chunks is detected quickly.

Example fix

// before
for (const chunk of chunks) { await h.writeResponse(chunk); }
// after
try {
  for (const chunk of chunks) {
    if (h.isCancelled) break;
    await h.writeResponse(chunk);
  }
} catch (e) {
  if (!/cancelled by the runtime/.test(String(e.message))) throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

function isCancelled(h): boolean {
  return (h as { isCancelled?: boolean }).isCancelled === true;
}
if (isCancelled(handler)) return; // skip write

Try / catch

try {
  await handler.writeResponse(chunk);
} catch (e) {
  if (e instanceof Error && e.message.includes('cancelled by the runtime')) { await cleanup(); return; }
  throw e;
}

Prevention

When it happens

Trigger: The runtime cancelled the request (client disconnect/timeout) and the handler subsequently calls writeResponse() — usually directly, or via streamResponse() — to emit another body chunk.

Common situations: Long-running streaming handlers (SSE-style output) where the user aborts mid-stream; loops that keep generating chunks without checking cancellation between iterations.

Related errors


AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09). Data as JSON: /api/errors/9bed55910c14474a. Report an issue: GitHub.

Appendix: source

Thrown at nodejs/src/copilotRequestHandler.ts:595

    async startResponse(init: ResponseInit): Promise<void> {
        if (this.#started) {
            throw new Error("Copilot request response start() called twice.");
        }
        if (this.#finished) {
            throw new Error("Copilot request response already finished.");
        }
        this.#started = true;
        await this.#rpc().llmInference.httpResponseStart({
            requestId: this.requestId,
            status: init.status,
            statusText: init.statusText,
            headers: init.headers ?? {},
        });
    }

    async writeResponse(data: string | Uint8Array): Promise<void> {
        if (this.#cancelled) {
            throw new Error("Copilot request was cancelled by the runtime.");
        }
        if (!this.#started) {
            throw new Error("Copilot request response write() called before start().");
        }
        if (this.#finished) {
            throw new Error("Copilot request response write() called after end()/error().");
        }
        const isString = typeof data === "string";
        await this.#rpc().llmInference.httpResponseChunk({
            requestId: this.requestId,
            data: isString ? data : Buffer.from(data).toString("base64"),
            binary: !isString,
            end: false,
        });
    }

    async endResponse(): Promise<void> {
        if (this.#finished) {

View on GitHub (pinned to cd8cf15dc3)