Repository navigation
fix(sandbox): fail fast when attaching to a missing OpenSandbox PTY session - #3641
Merged
Merged
Conversation
hemildesai
marked this pull request as ready for review
September 23, 2026 00:41
ananthsub
approved these changes
Sep 23, 2026
Contributor
Author
|
/ok to test d2cb1a7 |
Contributor
Author
|
The three red checks are unrelated to this change. That conflict came in with #3592, whose server-suite shards were skipped. 🤖 Generated with Claude Code |
ananthsub
approved these changes
Sep 23, 2026
…ession
execd refuses a WebSocket attach to a session that does not exist with
the same 1008 close as one held by another client. After a pause on the
Kubernetes backend replaces the runtime, re-attaching to a pre-pause
session was therefore treated as a stale holder: the session's own
takeover retries (2+5+10s), the provider's retries, and a closing
sandbox-death check took about 95s on cell-3 before reporting a
misleading "already has an attached client".
attach_pty() now asks execd first (GET /pty/{id}). Only execd's own 404
(CONTEXT_NOT_FOUND) counts as missing: a proxy 404 while a route is still
registering, or a failed check, leaves the attach to proceed as before.
A missing session now fails in about 0.3s with "PTY session <id> not
found", with or without takeover.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Hemil Desai <hemild@nvidia.com>
hemildesai
force-pushed
the
hemild/fix-pty-attach-missing-session
branch
from
September 23, 2026 15:07
d2cb1a7 to
5af14a4
Compare
Contributor
Author
|
/ok to test 5af14a4 |
Contributor
|
🔄 Merge queue validation started! You can track the progress here: https://github.com/NVIDIA-NeMo/Gym/actions/runs/35881522695 |
This branch was previously deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed and why
Follow-up to #2636 (sandbox pause/resume). On cell-3, re-attaching to a PTY session opened before a pause took about 95s to fail, and the error was misleading:
On the Kubernetes backend, pause commits the rootfs and replaces the runtime, so the old session no longer exists. But execd answers a WebSocket attach to a missing session with the same
1008close it uses for a session held by another client. I checked this live: a random session id, a random id withtakeover=1, and a genuinely held session all close1008with an empty reason within 0.3s. So Gym treated it as a stale holder and waited out every retry: the session's own takeover retries (2+5+10s), the provider's retries, and a final sandbox-death check.execd's HTTP API does tell the two apart, which the same live probe showed:
GET /pty/<missing>404 {"code":"CONTEXT_NOT_FOUND","message":"pty session … not found"}GET /pty/<live>200 {"session_id":…,"running":true,…}OpenSandboxProvider.attach_pty()now makes thatGETbefore dialing. Only execd's own 404, with theCONTEXT_NOT_FOUNDcode, counts as missing. A proxy 404 while a route is still registering, or a failed check, lets the attach proceed exactly as before. A missing session now fails immediately withPTY session <id> not found, with or withouttakeover. Before, withouttakeover, a missing session was also misreported as "already has an attached client".Cost: one extra small GET per attach. Attaches are reconnect operations, not per-command.
No issue filed. This was found while validating #2636 end to end.
Validation
Unit tests (
test_opensandbox_pty.py,test_opensandbox_provider.py,test_sandbox.py): 246 passed. New cases cover:takeovervalues.Two existing tests now count the existence-check client.
pre-commit runon the changed files passes.Live on cell-3 (tenant namespace, Kubernetes backend), running the pause/resume e2e across two OS processes:
exec, foreground pathexec, background path (whatopensandbox.yamlenables)not found(was about 95s with "already has an attached client")A separate probe confirmed the normal case is unaffected. Detaching from a live session and re-attaching by id succeeds with and without
takeover, in about 0.6s, with shell state intact. All sandboxes were deleted afterwards.Rollout evidence: N/A. This is a sandbox provider change with no environment, agent, or benchmark behavior change.
Noticed, not changed here
The foreground
execpath appends the SDK's error to stderr, so a command that exits non-zero gets a syntheticCommandExecError: <code>line after its own stderr. This behavior dates from the original sandbox API, and it's out of scope here.🤖 Generated with Claude Code