github/copilot-sdk · error · RuntimeError

Copilot request response already finished.

Error message

Copilot request response already finished.

What it means

After the response has been finished (end_response/error called or the handler marked it finished), start_response() refuses to begin a new response on the same object. The `finished` flag is a terminal state in the response lifecycle: started -> writing -> finished. This prevents resurrecting a completed HTTP response on a request_id the runtime has already closed.

Solutions

  1. Check `response.finished` before attempting start_response(); do not start a response after the body stream has ended.
  2. Send errors before finishing: call error()/end only after all writes, and never start a new response afterwards.
  3. Create a new request/response exchange if you genuinely need to emit another HTTP response.

Example fix

// before
await response.write_response("chunk")
await response.end_response()
await response.start_response(500, "Error", {})  # finished

// after
if not response.finished:
    await response.write_response("chunk")
    await response.end_response()
else:
    raise RuntimeError("response already completed; cannot restart")
Defensive patterns

Strategy: validation

Validate before calling

if response.finished:
    return  # response already completed; nothing to start

Type guard

def is_startable(response) -> bool:
    return not getattr(response, "started", False) and not getattr(response, "finished", False)

Try / catch

try:
    await response.start_response(status, status_text, headers)
except RuntimeError as e:
    if "already finished" in str(e):
        logger.warning("attempted to restart finished response; ignoring")
    else:
        raise

Prevention

When it happens

Trigger: Calling start_response() after end_response()/error() was called; calling start_response() on a response object that _finalize already completed; attempting to restart a response to send a retry or error status after the body was fully streamed.

Common situations: Middleware that tries to convert an in-flight response into an error response after the fact; handlers that run cleanup/finalization before the caller finishes writing; reusing a cached response object across retries.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at python/copilot/copilot_request_handler.py:443

    def request_body(self) -> _BodyQueue:
        return self._queue

    def _require_rpc(self) -> ServerLlmInferenceApi:
        rpc = self._get_server_rpc()
        if rpc is None:
            raise RuntimeError("Copilot request response used after RPC connection closed.")
        return rpc

    async def start_response(
        self,
        status: int,
        status_text: str | None = None,
        headers: LlmInferenceHeaders | None = None,
    ) -> None:
        if self.started:
            raise RuntimeError("Copilot request response start() called twice.")
        if self.finished:
            raise RuntimeError("Copilot request response already finished.")
        self.started = True
        await self._require_rpc().http_response_start(
            LlmInferenceHTTPResponseStartRequest(
                headers=headers or {},
                request_id=self.request_id,
                status=status,
                status_text=status_text,
            )
        )

    async def write_response(self, data: str | bytes) -> None:
        if self.cancelled:
            raise RuntimeError("Copilot request was cancelled by the runtime.")
        if not self.started:
            raise RuntimeError("Copilot request response write() called before start().")
        if self.finished:
            raise RuntimeError("Copilot request response write() called after end()/error().")
        if isinstance(data, bytes):

View on GitHub (pinned to cd8cf15dc3)