github/copilot-sdk · error · RuntimeError

Copilot request response start() called twice.

Error message

Copilot request response start() called twice.

What it means

start_response() is the state-machine entry point for a Copilot request's HTTP response and must be called exactly once before streaming body data. The library sets a `started` flag after the first call and raises this RuntimeError on any subsequent call, since a single HTTP response can only begin once per request_id. This guards against double-issuing the LlmInferenceHTTPResponseStart RPC to the runtime.

Solutions

  1. Check `response.started` before calling start_response(), or track whether your code already started the response.
  2. Ensure only one code path (either _finalize or _stream_response_to_exchange) is responsible for starting the response.
  3. If you need to send headers again for a different response, create a fresh response/request instead of reusing the finished one.

Example fix

// before
await response.start_response(200, "OK", headers)
await response.start_response(200, "OK", headers)  # duplicate

// after
if not response.started:
    await response.start_response(200, "OK", headers)
Defensive patterns

Strategy: validation

Validate before calling

if response.started:
    raise RuntimeError("response already started; skipping duplicate start_response")

Type guard

def can_start(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 "called twice" not in str(e):
        raise

Prevention

When it happens

Trigger: Calling response.start_response() a second time on the same response object — e.g. calling it again after _finalize or after _stream_response_to_exchange has already invoked it, or wrapping start_response in retry logic that retries an already-successful call.

Common situations: Custom response pipelines that call start_response both explicitly and via a framework adapter; error-handling paths that try to start an error response after the success path already started it; accidental double-invocation when both _finalize and a streaming helper run.

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/34a983fd70e687eb. Report an issue: GitHub.

Appendix: source

Thrown at python/copilot/copilot_request_handler.py:441

    @property
    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:

View on GitHub (pinned to cd8cf15dc3)