openclaw - 💡(How to fix) Fix Read tool: ENOENT / false 'Path escapes sandbox root' on valid in-workspace paths (v2026.4.22)

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

The Read tool intermittently returns ENOENT and (more diagnostically) "Path escapes sandbox root (~/.openclaw/workspace)" for files that exist inside the configured sandbox root. The root-comparison appears to use a literal tilde-prefixed string (~/.openclaw/workspace) against a fully-expanded absolute path (/home/<user>/.openclaw/workspace/<file>), producing a false-positive "escape" verdict. Bash, Edit, and Write on the same paths work fine.

Version: OpenClaw 2026.4.22 (00bd2cf) Platform: Linux arm64 (DGX Spark GB10), kernel 6.17, Node v22.22.2, host sandbox (no container)

Error Message

Note: at 09:15:44 the same SESSION-STATE.md was read successfully (the offset-beyond-EOF error proves the file opened). 17 seconds later the same path is rejected as escaping the sandbox root. This is a regression within a single live session, not a missing-file problem. Alternative (or additional) cause: cold-start race in runRemoteScript — empty stdout from the remote [ -e ] check is silently coerced to "not exists" rather than raising a bridge error. 2. Surface the real reason in the tool error, not generic ENOENT. Distinguish "file not found" from "sandbox rejected" (e.g. EACCES/ESANDBOX) and include the configured root in the message.

Root Cause

The Read tool intermittently returns ENOENT and (more diagnostically) "Path escapes sandbox root (~/.openclaw/workspace)" for files that exist inside the configured sandbox root. The root-comparison appears to use a literal tilde-prefixed string (~/.openclaw/workspace) against a fully-expanded absolute path (/home/<user>/.openclaw/workspace/<file>), producing a false-positive "escape" verdict. Bash, Edit, and Write on the same paths work fine.

Version: OpenClaw 2026.4.22 (00bd2cf) Platform: Linux arm64 (DGX Spark GB10), kernel 6.17, Node v22.22.2, host sandbox (no container)

Fix Action

Workaround

Use Bash cat <path> for reads that fail with ENOENT despite the file existing on disk.

Code Example

09:15:25 [tools] read failed: ENOENT: no such file or directory, access '<workspace>/BOOTSTRAP.md'
09:15:44 [tools] read failed: Offset 115 is beyond end of file (114 lines total)         # SESSION-STATE.md opened OK here
09:16:01 [tools] read failed: Path escapes sandbox root (~/.openclaw/workspace): <workspace>/SESSION-STATE.md

---

access: async (absolutePath) => {
    if (!await params.bridge.stat({ filePath: absolutePath, cwd: params.root })) {
        throw createFsAccessError("ENOENT", absolutePath);
    }
}
RAW_BUFFERClick to expand / collapse

Summary

The Read tool intermittently returns ENOENT and (more diagnostically) "Path escapes sandbox root (~/.openclaw/workspace)" for files that exist inside the configured sandbox root. The root-comparison appears to use a literal tilde-prefixed string (~/.openclaw/workspace) against a fully-expanded absolute path (/home/<user>/.openclaw/workspace/<file>), producing a false-positive "escape" verdict. Bash, Edit, and Write on the same paths work fine.

Version: OpenClaw 2026.4.22 (00bd2cf) Platform: Linux arm64 (DGX Spark GB10), kernel 6.17, Node v22.22.2, host sandbox (no container)

Reproduction

In a fresh agent session, immediately after boot:

  1. Read({path: "<workspace>/BOOTSTRAP.md"})ENOENT: no such file or directory, access '<workspace>/BOOTSTRAP.md'
  2. Bash({command: "ls -la <workspace>/BOOTSTRAP.md"}) → file exists, regular file, readable
  3. Retry Read (same path) → still ENOENT
  4. ~30 s later, retry Read → succeeds

Gateway log evidence (load-bearing)

09:15:25 [tools] read failed: ENOENT: no such file or directory, access '<workspace>/BOOTSTRAP.md'
09:15:44 [tools] read failed: Offset 115 is beyond end of file (114 lines total)         # SESSION-STATE.md opened OK here
09:16:01 [tools] read failed: Path escapes sandbox root (~/.openclaw/workspace): <workspace>/SESSION-STATE.md

Note: at 09:15:44 the same SESSION-STATE.md was read successfully (the offset-beyond-EOF error proves the file opened). 17 seconds later the same path is rejected as escaping the sandbox root. This is a regression within a single live session, not a missing-file problem.

Suspected cause (code-level)

In dist/openclaw-tools-D2PgzZeK.js, createSandboxReadOperations.access():

access: async (absolutePath) => {
    if (!await params.bridge.stat({ filePath: absolutePath, cwd: params.root })) {
        throw createFsAccessError("ENOENT", absolutePath);
    }
}

bridge.stat() (in dist/sandbox-DA33PQCZ.js) returns null whenever:

  • remotePathExists() returns false (remote shell if [ -e "$1" ] evaluates to "0"), or
  • the sandbox-side root-containment check rejects the resolved target.

Both failure modes surface to the user as a generic ENOENT from access(). Only the gateway log shows the real reason ("Path escapes sandbox root").

Most likely the configured sandbox root is stored with a literal ~/ prefix on at least one code path, and the containment check is a string prefix compare against an expanded absolute path — fails as "escape" even when the target is provably inside the root.

Alternative (or additional) cause: cold-start race in runRemoteScript — empty stdout from the remote [ -e ] check is silently coerced to "not exists" rather than raising a bridge error.

Suggested fixes

  1. Normalise the sandbox root to an absolute path once at boot (path.resolve(os.homedir(), ...)). Containment checks should always compare expanded forms.
  2. Surface the real reason in the tool error, not generic ENOENT. Distinguish "file not found" from "sandbox rejected" (e.g. EACCES/ESANDBOX) and include the configured root in the message.
  3. Fail-loud on empty stdout from remotePathExists — don't silently treat it as "does not exist".
  4. Warm the bridge with a no-op stat on the workspace root during agent boot so the first bootstrap-read sequence doesn't ENOENT-then-recover.

Impact

  • Bootstrap reads (BOOTSTRAP.md, AGENTS.md, SOUL.md, SESSION-STATE.md, MEMORY.md) can ENOENT on the first call, starting the conversation with stale or no context.
  • Agents misdiagnose the failure to the user as "file doesn't exist" / fabricate explanations.
  • Easy to mask: Bash cat works, so any agent that knows to fall back routes around the bug silently, leaving it unfixed.

Workaround

Use Bash cat <path> for reads that fail with ENOENT despite the file existing on disk.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix Read tool: ENOENT / false 'Path escapes sandbox root' on valid in-workspace paths (v2026.4.22)