Recorded events cannot distinguish completed vs truncated SSE; mid-stream upstream failure records status=200 and returns an invalid second Response #67
Labels
No labels
accessibility
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
nsaspy/llm-log#67
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Two related capture-fidelity bugs on the HTTP streaming path:
Mid-stream upstream failure (
llm_log/proxy.py:488-493, main @ HEAD): afterdownstream.prepare(request)has already sent the upstream's real status (e.g. 200) to the client, the except branch buildsdownstream = web.Response(status=502, ...). Returning a second response for an already-prepared request is invalid in aiohttp, and the recorded CaptureEvent usesresponse_status— which still holds the connect-time upstream status (200), not what the client ultimately received. The recorded event and the client experience disagree.No stream-completeness signal: the proxy relays SSE chunks verbatim and records whatever accumulated. A stream the upstream ended silently (clean EOF mid-generation, no
data: [DONE], nofinish_reason) is recorded identically to a fully completed one — as status 200 with a big body.Corpus evidence (24h slice, 2026-09-06T03:39Z → 09-07T03:39Z, 6,430 events)
status=200whose response bodies are provably incomplete SSE: end mid-reasoningdelta,finish_reason:null, no[DONE], 121KB–716KB bodies (4c671736…Z.AI,e4a09d86…Modal,28f4de87…GMICloud,aadcae1d…AtlasCloud, plus a zero-frame stream4ea9686c…consisting only of: OPENROUTER PROCESSINGcomments).raiseat proxy.py:491-492 and are never recorded at all — 426 ×ClientConnectionResetErrorin the period).722235fc…) shows what proper failure looks like: OpenRouter in-stream error frame{"error":{"code":504,"message":"Upstream idle timeout exceeded","metadata":{"error_type":"timeout"}}}withfinish_reason:"error".[Errno 104] Connection reset by peer(pre-connect resets).Downstream consumers (failure detectors, the expert plane's outcome labeler #15) currently cannot tell "model finished" from "stream died halfway through a 716KB reasoning trace" without re-parsing bodies.
Suggested fix
CaptureEvent(e.g.stream_completed: bool, plus finalfinish_reasonif parseable) at relay end — cheap, deterministic.web.Response; write an SSE error frame /write_eof()if the transport is alive, and record the event with an explicitstatus_kind(e.g.upstream_midstream_error) instead of the connect-time status.raisepath, but consider recording a minimal aborted-request marker (see #61) so "client gave up because upstream stalled" is distinguishable later.Regression fixtures
[DONE]→ event must be marked incomplete.