Bug
When a provider sends an error event mid-stream (e.g., Anthropic's {"type": "error", "error": {"type": "overloaded_error", "message": "Overloaded"}}), the error is silently discarded. The consumer receives partial content with no indication that an error occurred.
Reproduction
The silent discard path:
stream_post() in http.py yields the error event (valid JSON ✅)
- Provider's
_parse_chunk_content() → None (not a recognized content event type)
- Provider's
_parse_chunk_usage() → None
- Provider's
_parse_chunk_finish_reason() → None
_parse_chunk() → None (all three returned None)
Stream.__anext__() silently skips it (if chunk is not None: ...)
- Error vanishes — never logged, never raised, never stored in metadata
This affects all SSE-based text providers: Anthropic, OpenAI, Google, Cohere, DeepSeek, Groq, Mistral, Moonshot, xAI, OpenResponses.
Additional Notes
SSE_EVENT_ERROR = "error" is defined in src/celeste/providers/anthropic/messages/config.py (line 51) but never imported or referenced anywhere — dead code.
http.py's stream_post() does not call raise_for_status() before iterating SSE events (unlike stream_post_ndjson which does).
- The only provider with any error detection is BytePlus Images (stuffs error into chunk metadata, doesn't raise) and Gradium TTS (raises, but WebSocket-based, not SSE).
Proposed Fix
Add error detection to the base streaming pipeline. Two options:
Option A — Provider streaming mixin (recommended):
Each provider's streaming mixin adds a _handle_stream_error(event_data) method that checks for provider-specific error event types and raises. Called at the start of _parse_chunk().
Option B — Base Stream.__anext__:
Add a generic check before _parse_chunk() that looks for common error patterns (event.get("error"), event.get("type") == "error").
Option A is preferred because error event formats differ across providers (Anthropic uses {"type": "error"}, OpenAI uses different patterns, etc.).
Affected Files
src/celeste/streaming.py — optionally add base error hook
src/celeste/providers/*/streaming.py — add _handle_stream_error() to each provider's streaming mixin
src/celeste/http.py — consider adding raise_for_status() to stream_post() for HTTP-level errors
🤖 Generated with Claude Code
Bug
When a provider sends an error event mid-stream (e.g., Anthropic's
{"type": "error", "error": {"type": "overloaded_error", "message": "Overloaded"}}), the error is silently discarded. The consumer receives partial content with no indication that an error occurred.Reproduction
The silent discard path:
stream_post()inhttp.pyyields the error event (valid JSON ✅)_parse_chunk_content()→None(not a recognized content event type)_parse_chunk_usage()→None_parse_chunk_finish_reason()→None_parse_chunk()→None(all three returned None)Stream.__anext__()silently skips it (if chunk is not None: ...)This affects all SSE-based text providers: Anthropic, OpenAI, Google, Cohere, DeepSeek, Groq, Mistral, Moonshot, xAI, OpenResponses.
Additional Notes
SSE_EVENT_ERROR = "error"is defined insrc/celeste/providers/anthropic/messages/config.py(line 51) but never imported or referenced anywhere — dead code.http.py'sstream_post()does not callraise_for_status()before iterating SSE events (unlikestream_post_ndjsonwhich does).Proposed Fix
Add error detection to the base streaming pipeline. Two options:
Option A — Provider streaming mixin (recommended):
Each provider's streaming mixin adds a
_handle_stream_error(event_data)method that checks for provider-specific error event types and raises. Called at the start of_parse_chunk().Option B — Base
Stream.__anext__:Add a generic check before
_parse_chunk()that looks for common error patterns (event.get("error"),event.get("type") == "error").Option A is preferred because error event formats differ across providers (Anthropic uses
{"type": "error"}, OpenAI uses different patterns, etc.).Affected Files
src/celeste/streaming.py— optionally add base error hooksrc/celeste/providers/*/streaming.py— add_handle_stream_error()to each provider's streaming mixinsrc/celeste/http.py— consider addingraise_for_status()tostream_post()for HTTP-level errors🤖 Generated with Claude Code