Correlate client-side command-stream cancellation with envd logs (shared request-id)
Summary
When a command stream (Process.Start, most visibly commands.run) is cancelled from the client side, there is no shared identifier to join the client-side reason with the server-side (envd) log line. Operators can only correlate by sandbox id + timestamp, which is ambiguous under concurrency.
This is the client-side half of the observability gap that the server-side change e2b-dev/runtime#3647 starts to address.
Background
envd runs the guest process on a context decoupled from the streaming RPC (context.Background()-derived), so cancelling the stream does not kill the process — it runs to completion. A client that stops reading the stream (request timeout, a sibling task cancelling, the caller exiting, or an explicit disconnect()) therefore produces, on the server:
Process start (server stream end) error="context canceled" error_code=... operation_id=17Two problems, one on each side:
- Server (envd): the log line cannot know why the client went away. e2b-dev/runtime#3647 improves this by downgrading client-cancel from ERROR to INFO, mapping the code correctly, and annotating the cancel phase — but it still cannot attribute the client reason.
- Client (SDK):
CommandHandle(_handle_events/wait/disconnect) logs nothing when the stream is cancelled or disconnected, even though the SDK already carries alogging.LoggerviaConnectionConfig. Anddisconnect()explicitly stops reading without killing the process — exactly the "process exited 0 but no result was collected" case — with no client-side trace.
The correlation gap
- The
operation_idin envd logs is assigned server-side (AssignOperationID, a monotonic counter). The client never sees it. - envd does not read any client-supplied request/correlation header (
AddRequestIDToContextonly assigns its own).
So there is no id today that appears in both the SDK logs and the envd logs. Joining them requires one.
Proposal
- SDK generates a per-call correlation id and sends it as a request header (e.g.
X-E2B-Request-Id) on the streaming RPCs. - envd reads that header (falling back to its own assigned id when absent) and includes it in the stream log lines alongside
operation_id. - SDK logs the local cancel cause (timeout / sibling-cancel / caller-exit / explicit
disconnect/ RPC error) via the existingConnectionConfig.logger, tagged with the same correlation id.
Result: the envd "server stream end" line and the SDK cancel log become joinable by id, and each line carries the half of the story the other side cannot see.
Scope / rollout
- Cross-repo: SDK (this repo,
e2b-dev/E2B) + envd (e2b-dev/runtime). Backward compatible — envd falls back to its own id when the header is absent, so older SDKs keep working. - Can land incrementally: (a) SDK-side cancel-cause logging alone is already useful (correlate by sandbox id + timestamp); (b) the shared header closes the loop.
Opening this to align on the header name and direction before implementing. Related server-side work: e2b-dev/runtime#3647.
Source: e2b-dev/E2B