﻿# Errors inside an OpenRouter stream: why HTTP 200 is insufficient

Handle OpenRouter errors after streaming starts by distinguishing HTTP success, event-level failure, partial output and a separately identified retry.

Author: Retrivium team
Updated: 2026-11-01
Canonical URL: https://retrivium.ai/journal/openrouter-stream-errors/
Language: en

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 outcome | Possible interface state |
| --- | --- |
| Normal protocol completion | Complete answer ready |
| Error after content fragments | Partial answer with an explicit interruption message |
| User cancellation | Keep or discard content under application rules |
| Unexplained connection end | Success 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](https://openrouter.ai/docs/api_reference/errors-and-debugging), [openrouter.ai — streaming](https://openrouter.ai/docs/api_reference/streaming).

Related guides: [Reading an OpenRouter streaming response incrementally](/journal/openrouter-streaming-client/), [Tool calling through OpenRouter: the model proposes, your app executes](/journal/openrouter-tool-calling/).
