Streaming Errors Across All AI Providers (2026) — Complete Directory — AI Error Hub
AI Error Hub / Categories / Streaming
Category hub · Cross-provider · Streaming

Streaming Errors Across All AI Providers — 2026 Guide

Streaming responses are how modern AI applications feel fast — but they fail in ways non-streaming requests don't. Mid-stream disconnects leave partial output. Chunks arrive out of order. Timeouts don't behave like request timeouts. Every provider handles streaming differently, with different chunk formats and different failure modes. This is the cross-provider directory of streaming errors.

Streaming responses are how modern AI applications feel fast — but they fail in ways non-streaming requests don't. Mid-stream disconnects leave partial output. Chunks arrive as delta JSON that must be accumulated before parsing. Tool call arguments arrive as fragmentary JSON that will crash any premature parser. Reasoning models have a long silent pause before first token. Content filters run post-stream. Every provider handles streaming differently, with different chunk formats and different failure modes. This page is the cross-provider directory: every streaming failure pattern we've documented across every provider, IDE tool, and gateway, grouped so you can find your specific error in seconds.

For related failure modes, see the Rate Limits, Authentication, Context Window, Timeouts, and Content Filter category hubs. For the underlying architectural patterns, see the Rate Limits pillar guide.

2026 streaming formats at a glance

Streaming formats differ meaningfully across providers — SSE with typed events (Claude), SSE with delta terminator (OpenAI), JSON array chunks (Gemini), model-specific event streams (Bedrock). Here's the 2026 landscape at a glance.

ProviderFormatTerminatorKeep-aliveKey events
Anthropic ClaudeSSE with JSON eventsmessage_stop eventping event every ~15smessage_start, content_block_delta, message_delta, message_stop
Anthropic Claude (tool use)SSE with partial JSON deltasmessage_stop eventping eventinput_json_delta chunks — must reassemble
OpenAI Chat CompletionsSSEdata: [DONE]None (client handles)delta.content, delta.tool_calls chunks
OpenAI Responses API (2026)SSEevent: doneNone (client handles)response.output_item.done, response.completed
Google GeminiJSON array chunksFinal chunk with finishReasonNone (short timeouts)candidates[0].content.parts + finishReason
AWS Bedrock InvokeModelWithResponseStreamModel-specific event streamModel-specific (e.g. message_stop for Claude)Noneboto3 iterator, chunk format varies per model
AWS Bedrock ConverseStreamNormalized event streammessageStop eventNonecontentBlockDelta, messageStop, metadata
Azure OpenAI (Front Door)SSEdata: [DONE]NoneSame as OpenAI + 60s Front Door cap
Azure OpenAI (Direct endpoint)SSEdata: [DONE]NoneBypasses Front Door for long streams
Gateways (LiteLLM/Portkey)Normalized SSENormalized terminatorNone (client handles)stream_timeout separate from request_timeout

Anthropic Claude

Claude uses SSE with typed JSON events — message_start, content_block_start, content_block_delta, content_block_stop, message_delta, message_stop. Ping events keep the connection alive every ~15 seconds. Streaming with tool use is the trickiest pattern: tool arguments arrive as input_json_delta chunks that you must accumulate and parse only once complete. Extended thinking events stream separately from regular content blocks.

OpenAI

OpenAI streams SSE with delta chunks. Chat Completions terminates with data: [DONE]. The Responses API (launched 2026) uses event-typed streaming with event: done as terminator. Streaming with structured outputs enforces the JSON schema at the end — chunks may look invalid until the final chunk. Streaming with reasoning models: reasoning tokens don't stream visibly, so there's a long pause before the first visible content chunk arrives.

Google Gemini

Gemini's streamGenerateContent returns JSON chunks (not SSE) with a candidates array. The finishReason field arrives in the final chunk — if it's SAFETY, the stream ended because of content filtering; you may already have partial output that violates the same filter. No keep-alive, so slow generators can time out client-side.

AWS Bedrock

Bedrock offers two streaming APIs: InvokeModelWithResponseStream (model-native format — chunk structure varies per model) and ConverseStream (normalized format across models). The critical Bedrock streaming gotcha: boto3's read_timeout is ignored on streaming responses. The iterator can hang indefinitely if the server stops sending events without closing the connection.

Azure OpenAI

Azure OpenAI streaming inherits OpenAI's SSE format but adds the Azure Front Door problem: streams routed through Front Door are capped at 60 seconds regardless of streaming activity. For long-generating responses, use direct-to-deployment endpoints. Content filtering runs post-stream (the whole accumulated response is filtered), so a streamed response can be fully generated then blocked at the terminator.

Streaming at other layers of the stack

Streaming isn't only a provider-layer concern. IDE tools rely on streaming for interactive feel and fail visibly when it breaks. Gateways add their own timeout policies and per-chunk latency overhead. Frameworks wrap streaming in callback protocols or generators that can swallow errors silently.

IDE Tools

IDE tools rely on streaming for interactive feel — Cursor shows code appearing character-by-character, Claude Code streams to terminal, Copilot streams inline suggestions. Streaming failures in IDE tools often manifest as "stuck" progress indicators or partially-inserted code that has to be manually cleaned up.

Gateway Layer

Gateways normalize streaming across providers and add their own timeout policies. LiteLLM has stream_timeout separate from request_timeout — misconfigured gateways can cut streams shorter than the underlying provider would. OpenRouter passes chunks through with additional latency (~25-40ms overhead per chunk cascades on long streams). Portkey captures streaming metrics per chunk for observability.

Framework Layer

Frameworks handle streaming via callback protocols (LangChain), event streams from graph nodes (LangGraph), and generator patterns (LlamaIndex). Framework-layer streaming failures typically involve callback exceptions swallowing errors, generator not properly closing on downstream errors, or streaming being disabled unintentionally by a wrapper component that doesn't support it.

Frequently asked questions

Why does my stream disconnect mid-response?
Common causes: (1) client-side read timeout too short — set separate stream_timeout longer than request_timeout. (2) Intermediate proxy (Cloudflare, Nginx, ALB) with buffering enabled — streaming works only if buffering is disabled at every hop. (3) Azure Front Door 60s cap for Azure OpenAI. (4) boto3 read_timeout ignored on Bedrock streaming — the stream can hang indefinitely if the server stops sending. (5) Genuine provider capacity issue during peak load.
Should I retry a failed stream?
Yes, but with two caveats. (1) You may have already received partial output — decide whether to preserve, discard, or reconcile with the retry. (2) Streams are not idempotent by default — the retry generates new tokens, not the missing suffix of the original. For long-generating workloads with partial-output recovery matters, log the completed portion and prompt the retry to continue from where the original stopped. Simpler workloads can just discard the partial and re-run.
How do I accumulate stream chunks correctly?
Different providers, different patterns. OpenAI: concatenate delta.content strings across chunks. Claude: append content_block_delta.text values within the same content_block. Gemini: concatenate parts[].text values across chunks. Bedrock: pattern varies per underlying model (use ConverseStream for normalized). Never assume word boundaries — tokens can split mid-word, and premature parsing (especially of JSON) will fail.
How is streaming with tool calls different from streaming plain text?
Tool call arguments arrive as JSON deltas that must be accumulated across chunks and parsed only when complete. On OpenAI, this is delta.tool_calls[].function.arguments accumulating into a full JSON string. On Claude, input_json_delta chunks reassemble into the tool's input JSON. Parsing partial JSON typically throws — buffer the entire tool_call before attempting to parse. Same pattern applies to structured outputs.
Why does my reasoning model stream have a long pause before the first token?
Reasoning tokens don't stream visibly by design. The model generates its reasoning phase first (potentially 30 seconds to several minutes), then starts streaming the visible response. If your UI shows a spinner during that phase and users perceive it as 'the model isn't working,' add a message like 'Reasoning through the problem...' or show the reasoning_tokens count if the API surfaces it during the stream. For UX-sensitive workloads, avoid high reasoning_effort on user-facing turns.
How do I distinguish 'stream ended cleanly' vs 'stream disconnected'?
Each provider has a terminator event. Claude: message_stop event. OpenAI Chat Completions: data: [DONE]. OpenAI Responses API: event: done. Gemini: final chunk with finishReason set. Bedrock ConverseStream: messageStop event. If you close the stream without seeing the terminator, treat it as a disconnect (partial response). If you see the terminator, treat it as a complete response even if it's short — the model may have finished early legitimately.
What about buffering in Cloudflare / Nginx / load balancers?
Every hop between your client and the provider needs streaming-friendly config. Cloudflare: enable 'Streaming' feature or use Argo Smart Routing. Nginx: proxy_buffering off and proxy_cache off on the relevant location block. AWS ALB: streaming works but you may need to increase idle timeout beyond default 60s. Any hop with default buffering will hold the entire response before delivering to the client — which defeats streaming entirely.
How do I observe streaming performance?
Instrument three metrics: (1) time-to-first-token (TTFT) — how long from request to first chunk arrival. (2) inter-token latency — average time between chunk arrivals. (3) total generation time — request to terminator. Slow TTFT often indicates provider prefill capacity. Slow inter-token latency indicates provider generation capacity. Together they diagnose whether latency is prefill-bound or generation-bound.
Should I always use streaming?
No. Streaming is better UX for user-facing chat and interactive tools. It's worse for programmatic workflows that just need the final response — non-streaming is simpler and avoids all these streaming-specific failure modes. Batch processing, structured extraction, and background tasks should generally NOT stream. Chat, coding tools, and other interactive UX generally should.
What's the difference between OpenAI's Chat Completions streaming and Responses API streaming?
Chat Completions uses simple SSE with data: [DONE] terminator and delta chunks. Responses API (launched 2026) uses event-typed streaming with structured event names (response.output_item.done, response.completed, etc.) and event: done as terminator. Responses API events carry more metadata per event but require a different parser. Chat Completions remains available; Responses is the new primary path for structured / stateful workloads.