fix(windows): repair OpenClaw ProcessContainer startup (NVBug 6782898) - #3475
prekshivyas wants to merge 1 commit into
Conversation
Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
Qualification before/after summaryNVBug: 6782898 — OpenClaw ProcessContainer startup failure and delayed error reporting Before: The target exited before binding its port, but the useful failure was surfaced only after approximately 299.5 seconds. The final result was a generic provisioning timeout / After: The relay races child exit directly against readiness and routes a bounded stderr/exit-status Qualification status: Early-exit/fail-fast scenario PASS; exact x64 OpenClaw EPERM end-to-end qualification pending. ARM64 build/check, five unsupported-feature matrices, relay contract tests (10), OpenClaw compatibility tests (6), focused control-channel tests (12), and the real root-denial test passed. The available ARM64 Node fails earlier with |
Summary
Fixes the two observable defects tracked by NVBug 6782898 in the supported Windows OpenClaw/MXC flow:
C:\underprocess_container; andBase:
origin/windowsatfb2980e077288b61ef03a2e6187e162d158526aa.Related Issue
NVBug 6782898. No GitHub issue required; this is an internally tracked Windows bug.
Root cause
toRealPath()before preload/application code can run. In the reportedProcessContainer, that attemptslstat("C:\\")and fails withEPERM; the existing capture script's later realpath shim cannot affect this pre-entrypoint lookup.tokio::net::TcpStream::connect()and only calledChild::try_wait()afterward. The ProcessContainer loopback connect can remain pending despite the Tokio timeout, starving the later exit check until the full ~300-second readiness budget expires. The relay then closed without an error event, so the driver replaced the useful error withspawner exited before its target became ready.summary.txt.Changes
--preserve-symlinks-mainbefore the capture main module. This avoids only Node's pre-entrypoint main-module realpath; it does not add an ACL, capability, filesystem grant, or root traversal permission.Child::wait()directly against port readiness and shutdown. Isolate each loopback connect on Tokio's blocking pool and give the socket its own two-second deadline, avoiding process-handle polling behind a potentially stuck connect.target_failedevents carrying the exit status plus a bounded stderr tail (20 lines, 1,024 characters per line). Flush the event before relay exit and route the diagnostic into the sandbox failure.target_readyresult, preserve the caught error in its summary, synchronously check sandbox deletion, and wait for forward/gateway teardown.[openshell] version = 2header to the three OpenClaw example configs.Before / after evidence
Identical credential-redacted qualification shape on Yukon Windows ARM64, native ARM64
wxc-exec0.8.0, Node v22.22.3, OpenClaw 2026.7.1,process_container:fb2980e0)e369cf9f)--preserve-symlinks-main; child exited before bindingsandbox provisioning timed out after 300s; lifecycle reduced this tospawner exited before its target became readyProvisionFailed: target process exited before port 18889 came up: exit code: 0xc0000142The pinned ARM64 Node binary fails in this host's ProcessContainer loader with
STATUS_DLL_INIT_FAILED(0xc0000142) before JavaScript starts. Therefore this ARM64 machine cannot re-demonstrate the report's laterEPERM lstat C:\or complete the OpenClaw health check. The Node-side regression is covered by the durable argument-order/no-grant test and the fix follows Node's documented main-module resolution switch; a native x64 Windows qualification run remains required to validate the original EPERM path end to end. The early-exit defect is reproduced and fixed directly on ARM64.Security impact
C:\, grants only an unrelated workload directory, and verifies the sentinel read fails withAccess is deniedand never exposes its contents.Testing
mise run pre-commitpasses (not claimed: full test linking exhausted the host disk, and full Clippy reaches a pre-existingdriver.rs:819clippy::unused_selfwarning)Passed:
mise run --skip-tools windows:build:arm64(full release build)mise run --skip-tools windows:check:arm64(with an exact pinned Z3 4.16.0 local cache after the GitHub binary download returned HTTP 403)mise run --skip-tools windows:test:unsupported:arm64(all five unsupported-feature matrices)cargo test --release -p openshell-supervisor-relay --test control_channel_contract(10 passed; includes prompt exit-23/stderr propagation)cargo test --release -p openshell-driver-mxc --test openclaw_appcontainer_compat(6 passed)openshell-driver-mxccontrol_channeltests (12 passed, 82 filtered)cargo test --release -p openshell-driver-mxc --test wxc_exec_real pc_oneshot_unrelated_root_path_read_denied -- --ignored --exact --nocapture(passed on real ProcessContainer)openshell-supervisor-relayandopenshell-driver-mxcwith only the two confirmed base-tree lint allowances (clippy::unused_self,clippy::needless_update); all other warnings deniedcargo fmt --all -- --checkgit diff --checkrun-openclaw-forward-test.ps1Limitations observed:
mise run --skip-tools windows:test:arm64could not finish linking test binaries because the host ran out of disk (LNK1140/ OS error 112); no test assertion failed.mise run --skip-tools windows:test:mxc-real:arm64passed its eight dry-run cases, then the existingprobe_processcontainer_proxyhelper hung insidewxc-execeven forcmd /c exit 0; the new root-denial case was run and passed independently.windows:lint:arm64reaches a pre-existing, untouchedclippy::unused_selfwarning atdriver.rs:819; the affected crates pass targeted Clippy with that base lint and the existingneedless_updatebase lint allowed.Residual risk
EPERM lstat C:\path and successful OpenClaw health response because this Yukon host is ARM64 and the available x64 qualification inputs cannot run natively here.Checklist