Skip to content

Sandbox: add actionable guidance when python3 is missing#56785

Open
tonga54 wants to merge 1 commit intoopenclaw:mainfrom
tonga54:fix/issue-45108-sandbox-python3-guidance
Open

Sandbox: add actionable guidance when python3 is missing#56785
tonga54 wants to merge 1 commit intoopenclaw:mainfrom
tonga54:fix/issue-45108-sandbox-python3-guidance

Conversation

@tonga54
Copy link
Copy Markdown
Contributor

@tonga54 tonga54 commented Mar 29, 2026

Summary

Describe the problem and fix in 2–5 bullets:

  • Problem: when sandbox mutation helpers fail with python3: not found, users only see a raw shell error and cannot quickly recover.
  • Why it matters: write/edit flows fail with opaque errors, which looks like silent tool breakage and blocks normal agent workflows.
  • What changed: mutation execution paths now translate missing-python3 failures into actionable guidance that tells users to rebuild/update or configure a sandbox image with Python.
  • What did NOT change (scope boundary): no mutation protocol changes, no Docker image build logic changes, and no change to successful write/edit behavior.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

Root Cause / Regression History (if applicable)

For bug fixes or regressions, explain why this happened, not just what changed. Otherwise write N/A. If the cause is unclear, write Unknown.

  • Root cause: mutation helper execution assumes python3 exists inside the sandbox container; when missing, raw stderr bubbles up without actionable remediation guidance.
  • Missing detection / guardrail: no error translation layer for known sandbox dependency failures.
  • Prior context (git blame, prior PR, issue, or refactor if known): issue [Bug]: Sandbox write/edit fails on openclaw-sandbox:bookworm-slim with "moltbot-sandbox-fs: 2: python3: not found" #45108 reports repeated moltbot-sandbox-fs: 2: python3: not found failures during write/edit.
  • Why this regressed now: slim/older sandbox images can miss Python even though mutation helpers require it.
  • If unknown, what was ruled out: N/A.

Regression Test Plan (if applicable)

For bug fixes or regressions, name the smallest reliable test coverage that should have caught this. Otherwise write N/A.

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/agents/sandbox/fs-bridge.shell.test.ts
  • Scenario the test should lock in: when mutation helper stderr contains python3: not found, writeFile rejects with actionable guidance instead of opaque stderr.
  • Why this is the smallest reliable guardrail: the regression is in error mapping around sandbox command execution and is deterministic with mocked backend failures.
  • Existing test that already covers this (if any): existing fs bridge shell tests validate command shape, not dependency-failure messaging.
  • If no new test is added, why not: N/A.

User-visible / Behavior Changes

  • Write/edit failures caused by missing python3 now include explicit recovery guidance about sandbox image requirements.

Diagram (if applicable)

For UI changes or non-trivial logic flows, include a small ASCII diagram reviewers can scan quickly. Otherwise write N/A.

Before:
[write/edit] -> [python3 missing] -> [raw shell error]

After:
[write/edit] -> [python3 missing] -> [friendly actionable error + recovery guidance]

Security Impact (required)

  • New permissions/capabilities? (Yes/No) No
  • Secrets/tokens handling changed? (Yes/No) No
  • New/changed network calls? (Yes/No) No
  • Command/tool execution surface changed? (Yes/No) No
  • Data access scope changed? (Yes/No) No
  • If any Yes, explain risk + mitigation:

Repro + Verification

Environment

  • OS: macOS (dev)
  • Runtime/container: Node 24 / pnpm workspace
  • Model/provider: N/A
  • Integration/channel (if any): sandbox write/edit path
  • Relevant config (redacted): default sandbox test harness

Steps

  1. Simulate sandbox mutation helper failure with stderr containing python3: not found.
  2. Trigger writeFile through fs bridge.
  3. Verify thrown error message contains actionable python3/image guidance.

Expected

  • Error tells the operator exactly how to recover (image with python3), not just raw shell stderr.

Actual

  • Both local and remote fs bridge mutation paths now wrap this failure with friendly guidance.

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

pnpm test -- src/agents/sandbox/fs-bridge.shell.test.ts passes (9 tests).
pnpm check passes.

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios: mocked mutation failure surfaces friendly guidance; non-matching errors still propagate normally.
  • Edge cases checked: wrapper applies in both standard fs bridge and remote shell fs bridge mutation paths.
  • What you did not verify: live docker runtime with intentionally missing python3 image during manual interactive chat.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

Compatibility / Migration

  • Backward compatible? (Yes/No) Yes
  • Config/env changes? (Yes/No) No
  • Migration needed? (Yes/No) No
  • If yes, exact upgrade steps:

Risks and Mitigations

List only real risks for this PR. Add/remove entries as needed. If none, write None.

  • Risk: broad regex could accidentally match unrelated stderr lines containing python3: not found.
    • Mitigation: mapping only applies in mutation helper execution path where python3 is a required dependency.

Made with Cursor

@tonga54 tonga54 requested a review from a team as a code owner March 29, 2026 04:06
@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: S labels Mar 29, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Mar 29, 2026

Greptile Summary

This PR adds an error-translation layer that converts opaque python3: not found sandbox failures into actionable recovery guidance, covering both the local (SandboxFsBridgeImpl) and remote (RemoteShellSandboxFsBridge) mutation execution paths. The implementation is sound: execDockerRaw sets error.message = stderr.toString() when stderr is non-empty, so the regex check in toFriendlySandboxMutationError reliably matches real-world failures. The scope is correctly bounded — translation only activates in the mutation helper path via either a script-content guard ("python3 /dev/fd/3" in fs-bridge.ts) or method-level scoping (runMutation in remote-fs-bridge.ts).

  • New mutation-errors.ts module cleanly isolates detection and wrapping logic with a focused regex and a well-documented function.
  • fs-bridge.ts wraps runCommand inside runCheckedCommand and gates translation on the mutation script signature.
  • remote-fs-bridge.ts wraps runRemoteScript directly inside the dedicated runMutation method; non-python3 errors pass through unchanged.
  • Test correctly models the real error structure (error.message = stderr text) and asserts the friendly message is surfaced.
  • Minor: the new Error for the python3 case drops the original error's stack and code/stderr properties; using { cause: error } would preserve them for debugging.
  • Minor: test coverage is only added for the local bridge; the remote bridge path lacks a symmetric test.

Confidence Score: 5/5

Safe to merge — no logic errors, no behavioral regressions, and the happy path is unaffected.

All remaining findings are P2 (style/coverage suggestions). The core implementation is correct: error detection matches the real error structure, translation is properly scoped to mutation helpers only, and non-matching errors pass through unchanged. No P0 or P1 issues found.

No files require special attention. Optional: consider adding a { cause: error } option in mutation-errors.ts and a parallel test for RemoteShellSandboxFsBridge.

Important Files Changed

Filename Overview
src/agents/sandbox/mutation-errors.ts New helper module: detects python3: not found in error messages via regex and wraps with actionable guidance. Logic is correct — execDockerRaw sets error.message = stderr.toString() when stderr is non-empty, so the message-based check reliably catches real-world errors.
src/agents/sandbox/fs-bridge.ts Adds try/catch around runCommand inside runCheckedCommand, guarded by plan.script.includes("python3 /dev/fd/3") to scope translation only to mutation helper invocations. Non-mutation and stat paths are unaffected.
src/agents/sandbox/remote-fs-bridge.ts Wraps runRemoteScript inside the dedicated runMutation method with a try/catch calling toFriendlySandboxMutationError. No script-content guard needed since the catch is already inside the mutation-specific method. Non-matching errors pass through unchanged.
src/agents/sandbox/fs-bridge.shell.test.ts Adds one new test that mocks execDockerRaw to throw an error whose .message is the python3: not found string, matching how execDockerRaw actually structures docker stderr failures, and asserts the actionable guidance is surfaced.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/agents/sandbox/mutation-errors.ts
Line: 13-16

Comment:
**Consider preserving the original error as `cause`**

The new `Error` discards the original error's stack trace and `code`/`stderr` properties, which can make diagnosing edge-case failures harder for operators. Using the `cause` option keeps the chain intact while still surfacing the friendly message:

```suggestion
  return new Error(
    "Sandbox write/edit requires `python3` inside the sandbox container, but it is missing in the active image. Rebuild or update the sandbox image (or configure a custom sandbox image that includes `python3`). Original error: " +
      rawMessage,
    { cause: error },
  );
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: src/agents/sandbox/fs-bridge.shell.test.ts
Line: 144-171

Comment:
**No test coverage for `RemoteShellSandboxFsBridge` python3 detection**

The new test exercises the `SandboxFsBridgeImpl` path (`createSandboxFsBridge`) but not the `RemoteShellSandboxFsBridge` path (`createRemoteShellSandboxFsBridge`). Both paths were updated in this PR, and both have separate `try/catch` blocks calling `toFriendlySandboxMutationError`. A parallel test for the remote bridge would give symmetric coverage and ensure neither path regresses independently.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "Sandbox: improve missing-python3 write/e..." | Re-trigger Greptile

Comment on lines +13 to +16
return new Error(
"Sandbox write/edit requires `python3` inside the sandbox container, but it is missing in the active image. Rebuild or update the sandbox image (or configure a custom sandbox image that includes `python3`). Original error: " +
rawMessage,
);
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.

P2 Consider preserving the original error as cause

The new Error discards the original error's stack trace and code/stderr properties, which can make diagnosing edge-case failures harder for operators. Using the cause option keeps the chain intact while still surfacing the friendly message:

Suggested change
return new Error(
"Sandbox write/edit requires `python3` inside the sandbox container, but it is missing in the active image. Rebuild or update the sandbox image (or configure a custom sandbox image that includes `python3`). Original error: " +
rawMessage,
);
return new Error(
"Sandbox write/edit requires `python3` inside the sandbox container, but it is missing in the active image. Rebuild or update the sandbox image (or configure a custom sandbox image that includes `python3`). Original error: " +
rawMessage,
{ cause: error },
);
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/sandbox/mutation-errors.ts
Line: 13-16

Comment:
**Consider preserving the original error as `cause`**

The new `Error` discards the original error's stack trace and `code`/`stderr` properties, which can make diagnosing edge-case failures harder for operators. Using the `cause` option keeps the chain intact while still surfacing the friendly message:

```suggestion
  return new Error(
    "Sandbox write/edit requires `python3` inside the sandbox container, but it is missing in the active image. Rebuild or update the sandbox image (or configure a custom sandbox image that includes `python3`). Original error: " +
      rawMessage,
    { cause: error },
  );
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +144 to +171
it("surfaces actionable guidance when sandbox python3 is missing", async () => {
const bridge = createSandboxFsBridge({ sandbox: createSandbox() });
const baseImpl = mockedExecDockerRaw.getMockImplementation();
mockedExecDockerRaw.mockImplementation(async (...callArgs) => {
const args = callArgs[0] as string[];
if (getDockerScript(args).includes("operation = sys.argv[1]")) {
const message = "moltbot-sandbox-fs: 2: python3: not found";
const err = Object.assign(new Error(message), {
code: 127,
stdout: Buffer.alloc(0),
stderr: Buffer.from(message),
});
throw err;
}
if (baseImpl) {
return await baseImpl(...callArgs);
}
return {
stdout: Buffer.alloc(0),
stderr: Buffer.alloc(0),
code: 0,
};
});

await expect(bridge.writeFile({ filePath: "b.txt", data: "hello" })).rejects.toThrow(
/requires `python3` inside the sandbox container/i,
);
});
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.

P2 No test coverage for RemoteShellSandboxFsBridge python3 detection

The new test exercises the SandboxFsBridgeImpl path (createSandboxFsBridge) but not the RemoteShellSandboxFsBridge path (createRemoteShellSandboxFsBridge). Both paths were updated in this PR, and both have separate try/catch blocks calling toFriendlySandboxMutationError. A parallel test for the remote bridge would give symmetric coverage and ensure neither path regresses independently.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/sandbox/fs-bridge.shell.test.ts
Line: 144-171

Comment:
**No test coverage for `RemoteShellSandboxFsBridge` python3 detection**

The new test exercises the `SandboxFsBridgeImpl` path (`createSandboxFsBridge`) but not the `RemoteShellSandboxFsBridge` path (`createRemoteShellSandboxFsBridge`). Both paths were updated in this PR, and both have separate `try/catch` blocks calling `toFriendlySandboxMutationError`. A parallel test for the remote bridge would give symmetric coverage and ensure neither path regresses independently.

How can I resolve this? If you propose a fix, please make it concise.

@openclaw-barnacle
Copy link
Copy Markdown

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle Bot added the stale Marked as stale due to inactivity label Apr 30, 2026
@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented Apr 30, 2026

Codex review: needs changes before merge.

Summary
The PR adds a sandbox mutation error helper, wraps local and remote sandbox fs-bridge mutation execution, and adds a local bridge unit test for missing-python3 guidance.

Reproducibility: yes. The local path can be reproduced by mocking a Docker write to throw the current sandbox pinned mutation helper requires python3 or python failure, and the remote path by mocking runRemoteShellScript to throw python3: not found during writeFile.

Next step before merge
A narrow automated repair can rebase or replace the stale contributor PR because the remaining defect, files, and validation path are clear and no product or security decision is required first.

Security
Cleared: Security review cleared: the PR only changes sandbox mutation error mapping and a focused unit test, with no new dependency, permission, network, secret, workflow, lockfile, or install-script surface.

Review findings

  • [P2] Update the local detector for the current helper — src/agents/sandbox/fs-bridge.ts:298
Review details

Best possible solution:

Land a fresh current-main patch that maps both the current Docker mutation helper failure and the remote-shell python3 failure to actionable guidance, preserves the original error as cause, and covers both paths with targeted tests plus a changelog entry.

Do we have a high-confidence way to reproduce the issue?

Yes. The local path can be reproduced by mocking a Docker write to throw the current sandbox pinned mutation helper requires python3 or python failure, and the remote path by mocking runRemoteShellScript to throw python3: not found during writeFile.

Is this the best way to solve the issue?

No. The PR's goal is right, but the local detector targets the old helper marker; using the current mutation helper contract and adding symmetric remote coverage is the narrower maintainable fix.

Full review comments:

  • [P2] Update the local detector for the current helper — src/agents/sandbox/fs-bridge.ts:298
    The catch only rewrites errors when the script contains python3 /dev/fd/3, but current main's local mutation helper resolves python_cmd and execs "$python_cmd" -c .... After rebasing, local Docker write/edit failures from sandbox pinned mutation helper requires python3 or python will bypass this mapping, so the local half of the fix will not work.
    Confidence: 0.88

Overall correctness: patch is incorrect
Overall confidence: 0.84

Acceptance criteria:

  • pnpm test src/agents/sandbox/fs-bridge.shell.test.ts src/agents/sandbox/remote-fs-bridge.test.ts src/agents/sandbox/docker.test.ts
  • pnpm check:changed

What I checked:

  • PR local detector uses old helper marker: The proposed local wrapper only rewrites errors when the script contains python3 /dev/fd/3, which no longer matches the current local Docker mutation helper launch contract. (src/agents/sandbox/fs-bridge.ts:298, 8219dbccc312)
  • Current local helper resolves python_cmd: Current main resolves python_cmd, checks explicit Python paths plus command -v, emits sandbox pinned mutation helper requires python3 or python, and executes exec "$python_cmd" -c "$python_script" "$@". (src/agents/sandbox/fs-bridge-mutation-helper.ts:318, 929df0f5567f)
  • Current local bridge has no friendly missing-Python wrapper: runCheckedCommand() still returns this.runCommand(...) directly on current main, so helper failures are not translated in this path. (src/agents/sandbox/fs-bridge.ts:259, 929df0f5567f)
  • Current remote bridge still returns raw mutation failure: The remote-shell bridge still launches python3 /dev/fd/3 and returns runRemoteScript directly without the PR's catch/wrap layer. (src/agents/sandbox/remote-fs-bridge.ts:481, 929df0f5567f)
  • Related default-image fix shipped separately: The changelog records the shipped Docker default-image fix that preserves Python tooling and directs users to build the default image, but that does not cover this PR's remote-shell guidance path. (CHANGELOG.md:951, a448042c2edd)
  • Security-sensitive surfaces unchanged by PR diff: The PR touches only sandbox fs-bridge code and a focused test; it does not modify workflows, dependencies, lockfiles, install scripts, permissions, package publishing metadata, or secret handling. (8219dbccc312)

Likely related people:

  • vincentkoc: Authored the shipped default sandbox image fallback fix and current blame/history ties him to the central sandbox mutation, Docker image, and remote fs bridge files. (role: recent related maintainer; confidence: high; commits: 47dc9f7fc0b9, 9c0c0ed12746; files: src/agents/sandbox/docker.ts, src/agents/sandbox/docker.test.ts, src/agents/sandbox/fs-bridge-mutation-helper.ts)
  • steipete: Has prior merged work on sandbox image recovery and doctor repair paths, plus the latest release tag carrying the related sandbox changelog entry. (role: adjacent sandbox recovery maintainer; confidence: medium; commits: 94da41dc5266, 718299b25a05, a448042c2edd; files: docs/docker.md, docs/doctor.md, src/commands/doctor.ts)

Remaining risk / open question:

  • A replacement patch must keep the translation scoped to sandbox mutation helpers so unrelated backend failures continue to surface unchanged.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 929df0f5567f.

@openclaw-barnacle openclaw-barnacle Bot removed the stale Marked as stale due to inactivity label May 1, 2026
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.

[Bug]: Sandbox write/edit fails on openclaw-sandbox:bookworm-slim with "moltbot-sandbox-fs: 2: python3: not found"

1 participant