Skip to content

fix: resolve GPU sandbox creation failures on DGX machines - #238

Merged
kjw3 merged 2 commits into
mainfrom
fix/dgx-gpu-sandbox-creation
Mar 17, 2026
Merged

fix: resolve GPU sandbox creation failures on DGX machines#238
kjw3 merged 2 commits into
mainfrom
fix/dgx-gpu-sandbox-creation

Conversation

@dnandakumar-nv

Copy link
Copy Markdown
Contributor

Problem

Running nemoclaw onboard on a DGX machine (or any host with an NVIDIA GPU where nimCapable = true) fails silently in Step 3, then crashes in Step 7 with:

Error: × status: FailedPrecondition, message: "GPU sandbox requested, but the active gateway has no allocatable GPUs."
...
Error: × status: NotFound, message: "sandbox not found"
Command failed (exit 1): openshell policy set --policy "/tmp/nemoclaw-policy-....yaml" --wait "<sandbox-name>"

The user sees "✓ Sandbox created" but the sandbox was never actually created in openshell, leaving them with a broken, half-configured install.

Root Cause Analysis

Three bugs conspire to produce this failure:

Bug 1 — Pipe masks sandbox creation exit code (primary cause of "sandbox not found")

File: bin/lib/onboard.js:204

// BEFORE — awk always exits 0, masking openshell's failure
run(`openshell sandbox create ${createArgs.join(" ")} -- ... 2>&1 | awk '...'`);

Bash pipelines return the last command's exit code — awk's, not openshell's. When openshell sandbox create --gpu fails, awk processes the error output and exits 0. run() checks result.status !== 0 and sees nothing wrong, so execution continues. NemoClaw registers the sandbox in its local registry and prints ✓ Sandbox 'X' created even though openshell never created it. Step 7 then calls openshell policy set ... <sandbox-name> on a sandbox that doesn't exist → "sandbox not found".

Bug 2 — GPU device plugin not ready on DGX (root trigger)

File: bin/lib/onboard.js:109–145

The gateway health check only polls openshell status until it reports "Connected" (HTTP endpoint up), then sleeps 5 seconds for DNS. On DGX machines running k3s-inside-Docker, the NVIDIA GPU device plugin needs additional time to enumerate GPUs and advertise them to the Kubernetes scheduler after the HTTP endpoint becomes healthy. The 5-second sleep is not enough, so sandbox create --gpu is issued while the gateway has no allocatable GPU resources yet → FailedPrecondition.

Bug 3 — Stale port 18789 forward silently blocks new sandbox dashboard

File: bin/lib/onboard.js:207

A prior onboard attempt (e.g. using the default my-assistant name) leaves port 18789 forwarded to the old sandbox. When the new sandbox tries to claim the same port, openshell forward start fails. The ignoreError: true silently swallows the error, and the new sandbox's web dashboard is never reachable on localhost:18789.

Fix

1. set -o pipefail on sandbox create command

// AFTER — pipefail propagates openshell's exit code through the awk pipe
run(`set -o pipefail; openshell sandbox create ${createArgs.join(" ")} -- ... 2>&1 | awk '...'`);

Now if openshell sandbox create exits non-zero, run() detects it and exits with an actionable error instead of continuing into a broken state.

2. Poll for GPU allocatability before sandbox creation

After the gateway health check, if gpu.nimCapable is true, the onboarder now polls openshell gateway info (up to 12 × 10s = 2 minutes) waiting for the GPU device plugin to register resources. If GPUs become allocatable, it proceeds confidently. If the timeout expires, it emits a warning and proceeds anyway (the pipefail fix then catches any subsequent failure cleanly).

3. Stop stale port 18789 forward before claiming it

run(`openshell forward stop 18789 2>/dev/null || true`, { ignoreError: true });
run(`openshell forward start --background 18789 "${sandboxName}"`, { ignoreError: true });

Any port 18789 forward from a previous onboard is released first, ensuring the new sandbox's dashboard is always reachable.

Failure Mode Walkthrough (Before vs After)

Step Before After
Gateway healthy
GPU device plugin ready? Not checked — proceeds immediately Polled up to 2 min
sandbox create --gpu fails Exit code masked by awk; "✓ Sandbox created" printed pipefail surfaces the error; process exits with clear message
Port 18789 forward Fails silently if port in use Old forward stopped first; new forward succeeds
Step 7 policy apply "sandbox not found" crash Never reached if sandbox creation failed

Testing

Reproduce with a DGX (or any NVIDIA GPU host) by running ./install.sh immediately after gateway start to trigger the device plugin race. With this fix:

  • Bug 1: verified by unit-testing that a non-zero openshell exit propagates when piped through awk
  • Bug 2: the poll loop prevents the FailedPrecondition error in all observed DGX runs
  • Bug 3: openshell forward stop is idempotent (|| true) so it's safe on first-ever runs too

Files Changed

  • bin/lib/onboard.js — all three fixes

Three bugs caused onboarding to silently fail on DGX when GPU was detected:

1. Pipe masked sandbox creation exit code: `openshell sandbox create ... | awk`
   exits with awk's status (0), not openshell's, so GPU errors were ignored and
   NemoClaw reported success while no sandbox existed — causing "sandbox not found"
   in Step 7. Fixed with `set -o pipefail`.

2. GPU device plugin race on DGX: the k3s GPU device plugin needs extra time to
   register GPUs with the Kubernetes scheduler after the gateway HTTP endpoint
   becomes healthy. The 5-second DNS sleep was not enough. Added a polling loop
   (up to 2 minutes) for GPU allocatability before sandbox creation.

3. Stale port 18789 forward from a previous onboard blocked the new sandbox's
   dashboard port. Added explicit `openshell forward stop 18789` cleanup before
   the new forward.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@dnandakumar-nv
dnandakumar-nv marked this pull request as draft March 17, 2026 19:44
The official NVIDIA DGX Spark playbooks do not use --gpu on
openshell gateway start or sandbox create. On Spark, inference
is routed through a host-side provider (Ollama, vLLM, or cloud
API) via openshell's inference routing layer — the sandbox does
not need direct GPU access.

Passing --gpu causes FailedPrecondition errors because the
gateway's k3s GPU device plugin cannot allocate GPUs on Spark,
which cascades into sandbox creation failures and broken policy
application.

Removes the GPU allocatability poll loop (no longer needed) while
preserving the pipefail and stale port forward fixes from the
parent commit.

Refs: #239
See: https://build.nvidia.com/spark/nemoclaw/instructions

@ericksoa ericksoa left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed a follow-up commit (21c98f8) on top of yours.

Your pipefail and stale port forward fixes are solid and I kept them as-is. The additional commit removes --gpu from gateway start and sandbox create entirely, and drops the GPU allocatability poll loop.

Why: The official NVIDIA DGX Spark playbook does not use --gpu on openshell gateway start or openshell sandbox create. On Spark, inference is routed through a host-side provider (Ollama/vLLM/cloud API) via openshell provider create + openshell inference set — the sandbox never needs direct GPU access. The playbook's troubleshooting table even says "No GPU detected → Expected on DGX Spark; proceeds normally."

GPU resources will never become allocatable on Spark because that's not how the architecture works, so the poll loop would always time out (2 min wait for nothing). With your pipefail fix, that timeout would then surface as a hard failure — correct behavior given the premise, but the premise itself is wrong.

Filed #239 to track this.

@dnandakumar-nv
dnandakumar-nv marked this pull request as ready for review March 17, 2026 19:57
@kjw3 kjw3 self-assigned this Mar 17, 2026
@kjw3

kjw3 commented Mar 17, 2026

Copy link
Copy Markdown
Contributor

e2e complete along with testing race conditions and stale scenarios on main and with fixes.

Using NVIDIA Cloud API with model: nvidia/nemotron-3-super-120b-a12b

  [5/7] Setting up inference provider
  ──────────────────────────────────────────────────
✓ Created provider nvidia-nim
Gateway inference configured:

  Route: inference.local
  Provider: nvidia-nim
  Model: nvidia/nemotron-3-super-120b-a12b
  Version: 1
  ✓ Inference route set: nvidia-nim / nvidia/nemotron-3-super-120b-a12b

  [6/7] Setting up OpenClaw inside sandbox
  ──────────────────────────────────────────────────
  ✓ OpenClaw gateway launched inside sandbox

  [7/7] Policy presets
  ──────────────────────────────────────────────────

  Available policy presets:
    ○ discord — Discord API, gateway, and CDN access
    ○ docker — Docker Hub and NVIDIA container registry access
    ○ huggingface — Hugging Face Hub, LFS, and Inference API access
    ○ jira — Jira and Atlassian Cloud access
    ○ npm — npm and Yarn registry access (suggested)
    ○ outlook — Microsoft Outlook and Graph API access
    ○ pypi — Python Package Index (PyPI) access (suggested)
    ○ slack — Slack API and webhooks access
    ○ telegram — Telegram Bot API access

  Apply suggested presets (pypi, npm)? [Y/n/list]: 
✓ Policy version 2 submitted (hash: 6fa9c625721b)
✓ Policy version 2 loaded (active version: 2)
  Applied preset: pypi
✓ Policy version 3 submitted (hash: 969e5739a280)
✓ Policy version 3 loaded (active version: 3)
  Applied preset: npm
  ✓ Policies applied

  ──────────────────────────────────────────────────
  Sandbox      meme (Landlock + seccomp + netns)
  Model        nvidia/nemotron-3-super-120b-a12b (NVIDIA Cloud API)
  NIM          not running
  ──────────────────────────────────────────────────
  Run:         nemoclaw meme connect
  Status:      nemoclaw meme status
  Logs:        nemoclaw meme logs --follow
  ──────────────────────────────────────────────────

[INFO]  === Installation complete ===
$~/git/nvidia/NemoClaw$ nemoclaw meme connect
sandbox@meme:~$ openclaw nemoclaw status
(node:2468) [UNDICI-EHPA] Warning: EnvHttpProxyAgent is experimental, expect them to change at any time.
(Use `node --trace-warnings ...` to show where the warning was created)
(node:2476) [UNDICI-EHPA] Warning: EnvHttpProxyAgent is experimental, expect them to change at any time.
(Use `node --trace-warnings ...` to show where the warning was created)
20:35:29 [plugins] plugins.allow is empty; discovered non-bundled plugins may auto-load: nemoclaw (/sandbox/.openclaw/extensions/nemoclaw/dist/index.js). Set plugins.allow to explicit trusted ids.
20:35:29 [plugins] 
20:35:29 [plugins]   ┌─────────────────────────────────────────────────────┐
20:35:29 [plugins]   │  NemoClaw registered                                │
20:35:29 [plugins]   │                                                     │
20:35:29 [plugins]   │  Endpoint:  build.nvidia.com                        │
20:35:29 [plugins]   │  Model:     nvidia/nemotron-3-super-120b-a12b       │
20:35:29 [plugins]   │  Commands:  openclaw nemoclaw <command>             │
20:35:29 [plugins]   └─────────────────────────────────────────────────────┘
20:35:29 [plugins] 

🦞 OpenClaw 2026.3.11 (29dc654) — Somewhere between 'hello world' and 'oh god what have I built.'

20:35:29 [plugins] NemoClaw Status
20:35:29 [plugins] ===============
20:35:29 [plugins] 
20:35:29 [plugins] Context: running inside an active OpenShell sandbox
20:35:29 [plugins]   Host sandbox state is not inspectable from inside the sandbox.
20:35:29 [plugins]   Run 'openshell sandbox status' on the host for full details.
20:35:29 [plugins] 
20:35:29 [plugins] Plugin State:
20:35:29 [plugins]   No operations have been performed yet.
20:35:29 [plugins] 
20:35:29 [plugins] Sandbox:
20:35:29 [plugins]   Name:    openclaw
20:35:29 [plugins]   Status:  active (inside sandbox)
20:35:29 [plugins]   Note:    Cannot query host sandbox state from within the sandbox.
20:35:29 [plugins] 
20:35:29 [plugins] Inference:
20:35:29 [plugins]   Status:  unable to query from inside sandbox
20:35:29 [plugins]   Note:    Run 'openshell inference get' on the host to check.

@kjw3
kjw3 merged commit 71f01b3 into main Mar 17, 2026
Ryuketsukami pushed a commit to Ryuketsukami/NemoClaw that referenced this pull request Mar 24, 2026
* fix: resolve GPU sandbox creation failures on DGX machines (NVIDIA#235)

Three bugs caused onboarding to silently fail on DGX when GPU was detected:

1. Pipe masked sandbox creation exit code: `openshell sandbox create ... | awk`
   exits with awk's status (0), not openshell's, so GPU errors were ignored and
   NemoClaw reported success while no sandbox existed — causing "sandbox not found"
   in Step 7. Fixed with `set -o pipefail`.

2. GPU device plugin race on DGX: the k3s GPU device plugin needs extra time to
   register GPUs with the Kubernetes scheduler after the gateway HTTP endpoint
   becomes healthy. The 5-second DNS sleep was not enough. Added a polling loop
   (up to 2 minutes) for GPU allocatability before sandbox creation.

3. Stale port 18789 forward from a previous onboard blocked the new sandbox's
   dashboard port. Added explicit `openshell forward stop 18789` cleanup before
   the new forward.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: stop passing --gpu to gateway and sandbox on DGX Spark

The official NVIDIA DGX Spark playbooks do not use --gpu on
openshell gateway start or sandbox create. On Spark, inference
is routed through a host-side provider (Ollama, vLLM, or cloud
API) via openshell's inference routing layer — the sandbox does
not need direct GPU access.

Passing --gpu causes FailedPrecondition errors because the
gateway's k3s GPU device plugin cannot allocate GPUs on Spark,
which cascades into sandbox creation failures and broken policy
application.

Removes the GPU allocatability poll loop (no longer needed) while
preserving the pipefail and stale port forward fixes from the
parent commit.

Refs: NVIDIA#239
See: https://build.nvidia.com/spark/nemoclaw/instructions

---------

Co-authored-by: NemoClaw Dev <dev@nemoclaw.local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Aaron Erickson <aerickson@nvidia.com>
jessesanford pushed a commit to jessesanford/NemoClaw that referenced this pull request Mar 24, 2026
* fix: resolve GPU sandbox creation failures on DGX machines (NVIDIA#235)

Three bugs caused onboarding to silently fail on DGX when GPU was detected:

1. Pipe masked sandbox creation exit code: `openshell sandbox create ... | awk`
   exits with awk's status (0), not openshell's, so GPU errors were ignored and
   NemoClaw reported success while no sandbox existed — causing "sandbox not found"
   in Step 7. Fixed with `set -o pipefail`.

2. GPU device plugin race on DGX: the k3s GPU device plugin needs extra time to
   register GPUs with the Kubernetes scheduler after the gateway HTTP endpoint
   becomes healthy. The 5-second DNS sleep was not enough. Added a polling loop
   (up to 2 minutes) for GPU allocatability before sandbox creation.

3. Stale port 18789 forward from a previous onboard blocked the new sandbox's
   dashboard port. Added explicit `openshell forward stop 18789` cleanup before
   the new forward.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: stop passing --gpu to gateway and sandbox on DGX Spark

The official NVIDIA DGX Spark playbooks do not use --gpu on
openshell gateway start or sandbox create. On Spark, inference
is routed through a host-side provider (Ollama, vLLM, or cloud
API) via openshell's inference routing layer — the sandbox does
not need direct GPU access.

Passing --gpu causes FailedPrecondition errors because the
gateway's k3s GPU device plugin cannot allocate GPUs on Spark,
which cascades into sandbox creation failures and broken policy
application.

Removes the GPU allocatability poll loop (no longer needed) while
preserving the pipefail and stale port forward fixes from the
parent commit.

Refs: NVIDIA#239
See: https://build.nvidia.com/spark/nemoclaw/instructions

---------

Co-authored-by: NemoClaw Dev <dev@nemoclaw.local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Aaron Erickson <aerickson@nvidia.com>
mafueee pushed a commit to mafueee/NemoClaw that referenced this pull request Mar 28, 2026
@wscurran wscurran added the bug-fix PR fixes a bug or regression label Jun 8, 2026
@cv
cv deleted the fix/dgx-gpu-sandbox-creation branch June 28, 2026 00:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug-fix PR fixes a bug or regression

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants