LLM ROUTING

Errors inside an OpenRouter stream: why HTTP 200 is insufficient

In this article
THE QUICK TAKE

HTTP 200 confirms the start of a response, while successful completion must be established from the selected streaming protocol.

OpenRouter can begin a response with HTTP 200 and later report an error inside the stream. Once headers have been sent, the HTTP status cannot be replaced. A client that marks every 200 as completed success can therefore show truncated output and record misleading reliability statistics.

Separate response start and completion

Before streaming begins, an error can arrive as an ordinary unsuccessful HTTP response. Afterwards, the client must inspect the body or SSE events. Record the operation’s finish state explicitly rather than deriving it only from the initial status.

Keep timestamps for headers, first useful content and termination. These milestones answer different questions. An open connection can still fail before any useful answer, and a stream containing text can remain incomplete. Preserve that uncertainty until the expected completion event or a documented failure resolves it.

Interpret the chosen protocol

Chat Completions, Responses and other interfaces have different event structures. An SSE parser handles boundaries and comments; application logic must still understand whether an event contains text, completion, usage or an error. Do not treat every parsed JSON object as a successful content fragment.

Test incremental decoding with a controlled fixture: split an event across reads, combine several events in one read and place an error after a few content events. Such a fixture tests the client without repeatedly consuming model capacity. Keep it separate from a throughput benchmark.

Define the fate of partial output

Operation outcomePossible interface state
Normal protocol completionComplete answer ready
Error after content fragmentsPartial answer with an explicit interruption message
User cancellationKeep or discard content under application rules
Unexplained connection endSuccess remains unconfirmed

Choose whether partial text is useful to retain and make its status visible. Do not store it as a completed structured record or pass it to a dependent action without appropriate checks. A timeout and an explicit model refusal also need their own interpretations.

Give retries a new result boundary

If retrying is allowed, preserve the first attempt and identify the second separately. Avoid silently appending a new answer to the unfinished one or overwriting usage evidence. Bound the attempt count and total task deadline, and reconcile costs through available execution metadata.

Check the complete behavior before increasing load: parser, interface, logs and accounting should agree on the outcome. For infrastructure planning, distinguish this client failure handling from GPU capacity.

Official references: openrouter.ai — errors and debugging, openrouter.ai — streaming.

Related guides: Reading an OpenRouter streaming response incrementally, Tool calling through OpenRouter: the model proposes, your app executes.

← All articles