Description
The dashboard Request Health counters can report Completed while a streaming request later fails during stream finalization, leaving Failed: 0. This makes the dashboard misleading for interrupted or partially delivered streams.
Environment
- Headroom: 0.37.0
- Python: 3.13
- OS: Linux / WSL2
- Proxy: cache mode with code-aware enabled
- Proxy:
127.0.0.1:8787, upstream: localhost:4140
- Affected paths: streaming
/v1/messages and /v1/responses
Observed behavior
The dashboard showed:
- Completed: 815
- Failed: 0
- Rate Limited: 0
- Cached: 693
During the same proxy process, the logs repeatedly showed streaming cleanup/finalization errors:
UnicodeDecodeError: utf-8 codec cant decode byte 0xe5 ... unexpected end of data
- stack through
streaming.py finalization and parse_sse_events_from_byte_buffer
- accompanying
ClientDisconnect, CancelledError, and GeneratorExit
The failing decode occurs after the stream has started, while an incomplete UTF-8 sequence remains in the SSE byte buffer. The dashboard still counts the request under requests.total / Completed, while it is not counted by requests.failed.
Expected behavior
Request Health should distinguish at least:
- successfully completed responses;
- failures before a response starts;
- streams aborted or failing after delivery begins;
- rate-limited requests.
A request that starts streaming but fails during finalization should not silently appear as a successful Completed request with Failed: 0.
Suggested fix
Either rename Completed to a neutral name such as Processed or Recorded, or redefine it as an actual successful-response count. Add a visible Stream Aborted / Transport Errors counter (and ensure post-response streaming exceptions update it). Do not treat an incomplete UTF-8 buffer as a complete SSE event by appending a terminator and force-decoding it.
Reproduction notes
No standalone reproduction is available yet. This was observed in the live proxy logs and dashboard during normal streaming traffic. The relevant exception and call path are included above.
Related but not duplicates: #3405 (partial UTF-8 decode during interrupted SSE finalization), #1571 and #3083 (other failure-accounting/connection-error paths). This issue concerns the dashboard metric semantics and missing visibility for post-response stream failures.
Description
The dashboard Request Health counters can report
Completedwhile a streaming request later fails during stream finalization, leavingFailed: 0. This makes the dashboard misleading for interrupted or partially delivered streams.Environment
127.0.0.1:8787, upstream:localhost:4140/v1/messagesand/v1/responsesObserved behavior
The dashboard showed:
During the same proxy process, the logs repeatedly showed streaming cleanup/finalization errors:
UnicodeDecodeError: utf-8 codec cant decode byte 0xe5 ... unexpected end of datastreaming.pyfinalization andparse_sse_events_from_byte_bufferClientDisconnect,CancelledError, andGeneratorExitThe failing decode occurs after the stream has started, while an incomplete UTF-8 sequence remains in the SSE byte buffer. The dashboard still counts the request under
requests.total/Completed, while it is not counted byrequests.failed.Expected behavior
Request Health should distinguish at least:
A request that starts streaming but fails during finalization should not silently appear as a successful
Completedrequest withFailed: 0.Suggested fix
Either rename
Completedto a neutral name such asProcessedorRecorded, or redefine it as an actual successful-response count. Add a visibleStream Aborted/Transport Errorscounter (and ensure post-response streaming exceptions update it). Do not treat an incomplete UTF-8 buffer as a complete SSE event by appending a terminator and force-decoding it.Reproduction notes
No standalone reproduction is available yet. This was observed in the live proxy logs and dashboard during normal streaming traffic. The relevant exception and call path are included above.
Related but not duplicates: #3405 (partial UTF-8 decode during interrupted SSE finalization), #1571 and #3083 (other failure-accounting/connection-error paths). This issue concerns the dashboard metric semantics and missing visibility for post-response stream failures.