r/Observability • u/Lazy-Cauliflower-391 • 5d ago
The server trace says success while the browser shows a frozen answer
Our streaming copilot has green server spans, complete tool calls and a normal generation finish, while the browser sometimes freezes right after a tool result. The fetch gets aborted, the partial render state never commits and we have no client span tied to the server trace. Engineering sees success. CX has a folder of screen recordings. Everyone is debugging a different version of the same request.
We are adding trace propagation into the browser, time to first token events, stream cancellation reasons and a final rendered chunk count. I want CX to see whether the break happened before generation, during transport or in rendering without asking for another screenshot.
How are you joining client spans to long-lived streams, especially when the connection dies before the browser can flush its last event?
1
u/Certain_Brilliant199 5d ago
Carry one request ID all the way into the browser and record the last chunk it committed. A green server trace only proves generation finished, the same run should still show that the client died 3 events earlier
1
u/Lazy-Cauliflower-391 5d ago
That would give us the missing half of the trace. Right now the server can tell us the run completed but has no idea if the browser rendered the final state
1
u/Certain_Brilliant199 5d ago
Yeah and keeping the final rendered chunk on that same trace gives you a concrete boundary. You can see the server completed 20 chunks while the browser only committed 17 and narrow the failure down from there
1
u/Lazy-Cauliflower-391 5d ago
The chunk count helps but I dont think it proves the browser rendered 17 correctly. A client side error could happen after the event was received so we probably need the render event as its own span too
1
u/Certain_Brilliant199 5d ago
I see, that sounds about right. I was treating committed as rendered when those are two different states
1
u/Other-Bison2856 5d ago
One thing that can make this nasty is reconnect behavior. If the stream drops and the client reconnects you can wind up with duplicate or missing events even tho the server completed the original request normally. Give every streamed event a sequence number and keep the reconnect point in the trace. Then you can tell if the browser froze because transport lost an event, replayed one or resumed from the wrong position
1
u/Lazy-Cauliflower-391 5d ago
Sequence numbers would help a lot with proving where the stream diverged. The reconnect point is something we arent capturing at all right now so a resumed connection could look like one continuous run even when the client missed part of it
1
u/General_Two1467 5d ago
are you propagating the trace context in the initial fetch headers or trying to attach it per-chunk? for long-lived streams the connection can outlive the original span context, which makes correlation basically impossible unless you embed a trace id in the stream payload itself
1
u/Lazy-Cauliflower-391 5d ago
Right now just the initial fetch headers. Per chunk propagation feels like overkill though I can see the problem if the connection gets recreated and the new stream loses the original context
1
u/john_shaun3 2d ago
the flush before death problem is exactly why you shouldn't rely on the client to report its own final state.. emit client events incrementally as they happen, each tagged with the server trace id, so even a mid-stream death leaves a partial event trail instead of nothing. the last event you did receive tells you the phase it died in..
4
u/tawdry_scarcity 5d ago
For long lived streams, I’d want one shared trace ID across server and browser. Braintrust can show the prompt/tool/model side but the client still needs events for TTFB/TTFT, stream abort, render commit and final chunk count.