Skip to content

fix(edit): return accurate error for paths outside workspace root#30752

Closed
Jimmy-xuzimo wants to merge 1 commit intoopenclaw:mainfrom
Jimmy-xuzimo:fix/edit-tool-workspace-escape-error
Closed

fix(edit): return accurate error for paths outside workspace root#30752
Jimmy-xuzimo wants to merge 1 commit intoopenclaw:mainfrom
Jimmy-xuzimo:fix/edit-tool-workspace-escape-error

Conversation

@Jimmy-xuzimo
Copy link
Contributor

Summary

  • Problem: The Edit tool returned a misleading File not found error when given an absolute path outside the agent's workspace root. This was because toRelativePathInRoot throws "Path escapes workspace root" but the error was not being converted to an EACCES error code.
  • Why it matters: Users get confusing error messages when trying to edit files outside their workspace, making it hard to understand the actual issue.
  • What changed: Modified the access function in createHostEditOperations to catch the toRelativePathInRoot error and convert it to an EACCES error with a clear message, allowing pi-coding-agent's createEditTool to distinguish it from ENOENT (file not found).
  • What did NOT change: The overall file access behavior and security model remain unchanged.

Change Type

  • Bug fix

Scope

  • Gateway / orchestration

Linked Issue/PR

User-visible / Behavior Changes

  • Edit tool now returns Path escapes workspace root: <path> instead of File not found when attempting to edit files outside the workspace.

Security Impact

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No

Repro + Verification

Environment

  • OS: macOS (dev)
  • Runtime: Node.js 24.x

Steps

  1. Attempt to edit a file outside the workspace:
    { "tool": "edit", "path": "/path/outside/workspace/file.txt", "oldText": "a", "newText": "b" }

Expected

  • Error message should indicate the path is outside the workspace.

Actual

  • Before fix: File not found: /path/outside/workspace/file.txt
  • After fix: Path escapes workspace root: /path/outside/workspace/file.txt

Evidence

Commands run:

  • pnpm exec vitest run src/agents/pi-tools.read.workspace-escape-error.test.ts
  • pnpm exec vitest run src/agents/pi-tools.read.host-edit-access.test.ts
  • pnpm exec oxlint --type-aware src/agents/pi-tools.read.ts
  • pnpm exec oxfmt --check src/agents/pi-tools.read.ts

Human Verification

  • Verified scenarios: editing files outside workspace, editing non-existent files inside workspace, editing existing files inside workspace.
  • Edge cases checked: directory traversal (../outside/file.txt).
  • What I did not verify: Live multi-agent orchestration scenarios.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No

Failure Recovery

  • How to disable/revert: revert this PR commit.
  • Files/config to restore: src/agents/pi-tools.read.ts
  • Known bad symptoms: Edit tool returns misleading error messages again.

Risks and Mitigations

  • Risk: None identified. This change only improves error messaging without affecting functionality.

Contributed by @Jimmy-xuzimo

@openclaw-barnacle openclaw-barnacle bot added agents Agent runtime and tooling size: S labels Mar 1, 2026
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 1, 2026

Greptile Summary

Fixed misleading error message when Edit tool receives paths outside workspace root. Previously returned "File not found" when toRelativePathInRoot threw for escaped paths; now correctly returns "Path escapes workspace root" with EACCES error code.

  • Modified access function in createHostEditOperations (src/agents/pi-tools.read.ts:845-857) to catch toRelativePathInRoot errors and convert to EACCES with clear message
  • Added comprehensive test coverage for workspace boundary enforcement scenarios
  • Change is minimal, focused, and backwards-compatible (only improves error messaging)

Confidence Score: 5/5

  • This PR is safe to merge with no identified risks
  • The change is minimal and focused on improving error messaging without altering functionality. Comprehensive test coverage validates the fix for all scenarios (paths outside workspace, non-existent files inside workspace, directory traversal attempts). The implementation correctly converts workspace boundary violations to EACCES errors, allowing the Edit tool to distinguish them from ENOENT errors. No breaking changes or security concerns.
  • No files require special attention

Last reviewed commit: 12efc98

The Edit tool returned a misleading 'File not found' error when given an
absolute path outside the agent's workspace root. This was because
toRelativePathInRoot throws 'Path escapes workspace root' but the error
was not being converted to an EACCES error code.

This fix ensures that when a path is outside the workspace, the access
function throws an EACCES error with a clear 'Path escapes workspace root'
message, allowing pi-coding-agent's createEditTool to distinguish it from
ENOENT (file not found) and show the correct error message.

- Fixes openclaw#30724
- Related to openclaw#30711
- Adds tests for workspace escape error handling
@Jimmy-xuzimo Jimmy-xuzimo force-pushed the fix/edit-tool-workspace-escape-error branch from 4930c76 to 5d7ab61 Compare March 1, 2026 16:19
@Jimmy-xuzimo
Copy link
Contributor Author

@openclaw/maintainers @byungsker

Update: This PR has been updated:

  • Rebased onto latest main branch
  • All tests passing - verified with pnpm exec vitest run src/agents/pi-tools.read --reporter=verbose
  • Code quality checks passed - oxlint and oxfmt

This fix addresses issue #30724 where the Edit tool returned misleading "File not found" errors for paths outside workspace root. Now it correctly returns "Path escapes workspace root" with EACCES error code.

Ready for review and merge! 🚀


Contributed by @Jimmy-xuzimo

@openclaw-barnacle
Copy link

Please don’t spam-ping multiple maintainers at once. Be patient, or join our community Discord for help: https://discord.gg/clawd

thomasxm pushed a commit to thomasxm/openclaw that referenced this pull request Mar 1, 2026
path.resolve() treats ~ as a literal directory name, so ~/file.txt
resolved to <cwd>/~/file.txt instead of /home/user/file.txt. Add
expandHomePrefix() before path.resolve() in all affected tool path
resolution points:

- Host write operations (mkdir, writeFile) in non-workspace mode
- Host edit operations (readFile, writeFile, access) in non-workspace mode
- toRelativePathInRoot() workspace boundary validator (affects all tools)
- resolveWorkdir() for non-sandbox exec/bash working directory
- parseSandboxBindMount() for Docker bind mount host paths

The host read tool and sandbox tools already handled tilde via the
upstream library's expandPath().

Closes openclaw#30669
Related: openclaw#30782, openclaw#30788, openclaw#30744, openclaw#30770, openclaw#30756, openclaw#30753, openclaw#30752, openclaw#30747
thomasxm pushed a commit to thomasxm/openclaw that referenced this pull request Mar 1, 2026
path.resolve() treats ~ as a literal directory name, so ~/file.txt
resolved to <cwd>/~/file.txt instead of /home/user/file.txt. Add
expandHomePrefix() before path.resolve() in all affected tool path
resolution points:

- Host write operations (mkdir, writeFile) in non-workspace mode
- Host edit operations (readFile, writeFile, access) in non-workspace mode
- toRelativePathInRoot() workspace boundary validator (affects all tools)
- resolveWorkdir() for non-sandbox exec/bash working directory
- parseSandboxBindMount() for Docker bind mount host paths

The host read tool and sandbox tools already handled tilde via the
upstream library's expandPath().

Closes openclaw#30669
Related: openclaw#30782, openclaw#30788, openclaw#30744, openclaw#30770, openclaw#30756, openclaw#30753, openclaw#30752, openclaw#30747
thomasxm pushed a commit to thomasxm/openclaw that referenced this pull request Mar 1, 2026
path.resolve() treats ~ as a literal directory name, so ~/file.txt
resolved to <cwd>/~/file.txt instead of /home/user/file.txt. Add
expandHomePrefix() before path.resolve() in all affected tool path
resolution points:

- Host write operations (mkdir, writeFile) in non-workspace mode
- Host edit operations (readFile, writeFile, access) in non-workspace mode
- toRelativePathInRoot() workspace boundary validator (affects all tools)
- resolveWorkdir() for non-sandbox exec/bash working directory
- parseSandboxBindMount() for Docker bind mount host paths

The host read tool and sandbox tools already handled tilde via the
upstream library's expandPath().

Closes openclaw#30669
Related: openclaw#30782, openclaw#30788, openclaw#30744, openclaw#30770, openclaw#30756, openclaw#30753, openclaw#30752, openclaw#30747
thomasxm pushed a commit to thomasxm/openclaw that referenced this pull request Mar 1, 2026
path.resolve() treats ~ as a literal directory name, so ~/file.txt
resolved to <cwd>/~/file.txt instead of /home/user/file.txt. Add
expandHomePrefix() before path.resolve() in all affected tool path
resolution points:

- Host write operations (mkdir, writeFile) in non-workspace mode
- Host edit operations (readFile, writeFile, access) in non-workspace mode
- toRelativePathInRoot() workspace boundary validator (affects all tools)
- resolveWorkdir() for non-sandbox exec/bash working directory
- parseSandboxBindMount() for Docker bind mount host paths

The host read tool and sandbox tools already handled tilde via the
upstream library's expandPath().

Closes openclaw#30669
Related: openclaw#30782, openclaw#30788, openclaw#30744, openclaw#30770, openclaw#30756, openclaw#30753, openclaw#30752, openclaw#30747
thomasxm pushed a commit to thomasxm/openclaw that referenced this pull request Mar 1, 2026
path.resolve() treats ~ as a literal directory name, so ~/file.txt
resolved to <cwd>/~/file.txt instead of /home/user/file.txt. Add
expandHomePrefix() before path.resolve() in all affected tool path
resolution points:

- Host write operations (mkdir, writeFile) in non-workspace mode
- Host edit operations (readFile, writeFile, access) in non-workspace mode
- toRelativePathInRoot() workspace boundary validator (affects all tools)
- resolveWorkdir() for non-sandbox exec/bash working directory
- parseSandboxBindMount() for Docker bind mount host paths

The host read tool and sandbox tools already handled tilde via the
upstream library's expandPath().

Closes openclaw#30669
Related: openclaw#30782, openclaw#30788, openclaw#30744, openclaw#30770, openclaw#30756, openclaw#30753, openclaw#30752, openclaw#30747
thomasxm pushed a commit to thomasxm/openclaw that referenced this pull request Mar 1, 2026
path.resolve() treats ~ as a literal directory name, so ~/file.txt
resolved to <cwd>/~/file.txt instead of /home/user/file.txt. Add
expandHomePrefix() before path.resolve() in all affected tool path
resolution points:

- Host write operations (mkdir, writeFile) in non-workspace mode
- Host edit operations (readFile, writeFile, access) in non-workspace mode
- toRelativePathInRoot() workspace boundary validator (affects all tools)
- resolveWorkdir() for non-sandbox exec/bash working directory
- parseSandboxBindMount() for Docker bind mount host paths

The host read tool and sandbox tools already handled tilde via the
upstream library's expandPath().

Closes openclaw#30669
Related: openclaw#30782, openclaw#30788, openclaw#30744, openclaw#30770, openclaw#30756, openclaw#30753, openclaw#30752, openclaw#30747
@steipete
Copy link
Contributor

steipete commented Mar 2, 2026

Superseded by a landed fix on .

Closing this PR as duplicate/superseded to keep one canonical patch path.

@steipete steipete closed this Mar 2, 2026
@steipete
Copy link
Contributor

steipete commented Mar 2, 2026

Correction with exact refs:

thomasxm pushed a commit to thomasxm/openclaw that referenced this pull request Mar 3, 2026
path.resolve() treats ~ as a literal directory name, so ~/file.txt
resolved to <cwd>/~/file.txt instead of /home/user/file.txt. Add
expandHomePrefix() before path.resolve() in all affected tool path
resolution points:

- Host write operations (mkdir, writeFile) in non-workspace mode
- Host edit operations (readFile, writeFile, access) in non-workspace mode
- toRelativePathInRoot() workspace boundary validator (affects all tools)
- resolveWorkdir() for non-sandbox exec/bash working directory
- parseSandboxBindMount() for Docker bind mount host paths

The host read tool and sandbox tools already handled tilde via the
upstream library's expandPath().

Closes openclaw#30669
Related: openclaw#30782, openclaw#30788, openclaw#30744, openclaw#30770, openclaw#30756, openclaw#30753, openclaw#30752, openclaw#30747
thomasxm pushed a commit to thomasxm/openclaw that referenced this pull request Mar 3, 2026
path.resolve() treats ~ as a literal directory name, so ~/file.txt
resolved to <cwd>/~/file.txt instead of /home/user/file.txt. Add
expandHomePrefix() before path.resolve() in all affected tool path
resolution points:

- Host write operations (mkdir, writeFile) in non-workspace mode
- Host edit operations (readFile, writeFile, access) in non-workspace mode
- toRelativePathInRoot() workspace boundary validator (affects all tools)
- resolveWorkdir() for non-sandbox exec/bash working directory
- parseSandboxBindMount() for Docker bind mount host paths

The host read tool and sandbox tools already handled tilde via the
upstream library's expandPath().

Closes openclaw#30669
Related: openclaw#30782, openclaw#30788, openclaw#30744, openclaw#30770, openclaw#30756, openclaw#30753, openclaw#30752, openclaw#30747
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Edit tool returns misleading 'File not found' for paths outside workspace sandbox

2 participants