openclaw - ✅(Solved) Fix [Bug]: `fs-safe` writes silently fail in Docker with misleading "path is not a regular file under root" when `python3` is not in PATH [1 pull requests, 1 participants]

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…
GitHub stats
openclaw/openclaw#72362Fetched 2026-04-27 05:30:56
View on GitHub
Comments
0
Participants
1
Timeline
3
Reactions
0
Participants
Timeline (top)
labeled ×2cross-referenced ×1

writeFileWithinRoot and openFileWithinRoot in dist/fs-safe-*.js require python3 to be available in PATH because they spawn a Python subprocess for atomic file writes (using os.open with O_NOFOLLOW, dir_fd-based path walking, and os.replace). When python3 is missing — which is the default in node:24-bookworm-slim and similar slim Docker base images — the underlying error (spawn python3 ENOENT) is swallowed by normalizePinnedWriteError and surfaces as the misleading message: path is not a regular file under root This breaks several real user-facing features:

The bundled session-memory hook never writes session summaries to memory/ on /new or /reset. Agents with tools.fs.workspaceOnly: true cannot use edit, write, or apply_patch — even on files that are clearly inside their workspace. Any other code path that calls writeFileWithinRoot or openFileWithinRoot fails identically.

The misleading error message strongly suggests a path/permission/symlink problem, leading users (and AI agents debugging this) down hours of dead-end investigation. There is also no mention of python3 as a requirement in the official Docker installation docs.

Error Message

Reproduction output

Direct call to writeFileWithinRoot from a fresh node:lts-bookworm-slim container without python3: FAIL message: path is not a regular file under root FAIL cause: Error: spawn python3 ENOENT at ChildProcess._handle.onexit (node:internal/child_process:287:19) at onErrorNT (node:internal/child_process:508:16) at process.processTicksAndRejections (node:internal/process/task_queues:90:21) { errno: -2, code: 'ENOENT', syscall: 'spawn python3', path: 'python3', spawnargs: [ '-c', '<python helper script for atomic O_NOFOLLOW write>', ... ] } FAIL stack: SafeOpenError: path is not a regular file under root at normalizePinnedWriteError (file:///usr/local/lib/node_modules/openclaw/dist/fs-safe-CtRwwu0C.js:954:9) at file:///usr/local/lib/node_modules/openclaw/dist/fs-safe-CtRwwu0C.js:779:9 at process.processTicksAndRejections (node:internal/process/task_queues:104:5) at async writeFileWithinRoot (file:///usr/local/lib/node_modules/openclaw/dist/fs-safe-CtRwwu0C.js:767:19)

Gateway log when session-memory hook fires (e.g. on /new)

Only the headline is logged; the real cause is dropped: 2026-04-26T18:50:44.021+02:00 [hooks/session-memory] Failed to save session memory 2026-04-26T20:01:08.348+02:00 [hooks/session-memory] Failed to save session memory

Verification after installing python3

After apt-get install -y python3 in the same container, the same call succeeds: $ docker exec -u node openclaw node --input-type=module -e '...' OK undefined

The session-memory hook now writes files to ~/.openclaw/workspace/memory/ again on /new, and tools.fs.workspaceOnly: true no longer blocks edit / write on in-workspace files.

Affected memory/ directory state

Before fix — files in workspace memory/ directory after the bug appeared on 2026-04-15 are only the daily files written by the agent itself (via the edit/write tools when workspaceOnly: false), no session-memory-hook outputs. Last successful hook output: 2026-04-14.

Root Cause

writeFileWithinRoot and openFileWithinRoot in dist/fs-safe-*.js require python3 to be available in PATH because they spawn a Python subprocess for atomic file writes (using os.open with O_NOFOLLOW, dir_fd-based path walking, and os.replace). When python3 is missing — which is the default in node:24-bookworm-slim and similar slim Docker base images — the underlying error (spawn python3 ENOENT) is swallowed by normalizePinnedWriteError and surfaces as the misleading message: path is not a regular file under root This breaks several real user-facing features:

Fix Action

Fix / Workaround

The bundled session-memory hook never writes session summaries to memory/ on /new or /reset. Agents with tools.fs.workspaceOnly: true cannot use edit, write, or apply_patch — even on files that are clearly inside their workspace. Any other code path that calls writeFileWithinRoot or openFileWithinRoot fails identically.

  • Anyone running OpenClaw in a Docker container based on a slim image without python3 (notably node:*-slim, which is the recommended base for production deployments).
  • All code paths that go through writeFileWithinRoot / openFileWithinRoot in dist/fs-safe-*.js. Confirmed affected:
    • The bundled session-memory hook (silently fails on every /new and /reset).
    • Agent file tools edit, write, apply_patch when tools.fs.workspaceOnly: true is set.
  • Independent of channel (Telegram, WebChat, etc.), independent of model/provider.

Workaround for affected users

PR fix notes

PR #72531: fix(fs-safe): surface clear error when python3 is missing

Description (problem / solution / changelog)

Summary

Fixes #72362 — writeFileWithinRoot silently fails with misleading path is not a regular file under root when python3 is not installed.

Root cause

normalizePinnedWriteError() wraps all errors from the pinned write helper into a generic SafeOpenError('invalid-path', 'path is not a regular file under root'). When the real cause is spawn python3 ENOENT (missing python3 binary), the error message leads users down a dead-end investigation of paths, permissions, and symlinks.

Fix

Added detection in normalizePinnedWriteError() for ENOENT errors related to python3. When detected, surfaces a clear actionable message:

pinned write failed: python3 is not installed. Install python3 (e.g. `apt-get install python3`) or use a base image that includes it.

Checks both the direct error and error.cause since the ENOENT can appear at either level depending on the spawn path.

Changes

  • src/infra/fs-safe.ts: Enhanced normalizePinnedWriteError() to detect python3 ENOENT

Testing

  • TypeScript compilation passes
  • Existing fs-safe.test.ts tests for python3 ENOENT scenarios continue to pass

Changed files

  • src/infra/fs-safe.test.ts (modified, +71/-0)
  • src/infra/fs-safe.ts (modified, +35/-0)

Code Example

### Reproduction output

Direct call to `writeFileWithinRoot` from a fresh `node:lts-bookworm-slim` container without `python3`:
FAIL message: path is not a regular file under root
FAIL cause: Error: spawn python3 ENOENT
at ChildProcess._handle.onexit (node:internal/child_process:287:19)
at onErrorNT (node:internal/child_process:508:16)
at process.processTicksAndRejections (node:internal/process/task_queues:90:21) {
errno: -2,
code: 'ENOENT',
syscall: 'spawn python3',
path: 'python3',
spawnargs: [ '-c', '<python helper script for atomic O_NOFOLLOW write>', ... ]
}
FAIL stack: SafeOpenError: path is not a regular file under root
at normalizePinnedWriteError (file:///usr/local/lib/node_modules/openclaw/dist/fs-safe-CtRwwu0C.js:954:9)
at file:///usr/local/lib/node_modules/openclaw/dist/fs-safe-CtRwwu0C.js:779:9
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
at async writeFileWithinRoot (file:///usr/local/lib/node_modules/openclaw/dist/fs-safe-CtRwwu0C.js:767:19)

### Gateway log when `session-memory` hook fires (e.g. on `/new`)

Only the headline is logged; the real cause is dropped:
2026-04-26T18:50:44.021+02:00 [hooks/session-memory] Failed to save session memory
2026-04-26T20:01:08.348+02:00 [hooks/session-memory] Failed to save session memory

### Verification after installing `python3`

After `apt-get install -y python3` in the same container, the same call succeeds:
$ docker exec -u node openclaw node --input-type=module -e '...'
OK undefined

The `session-memory` hook now writes files to `~/.openclaw/workspace/memory/` again on `/new`, and `tools.fs.workspaceOnly: true` no longer blocks `edit` / `write` on in-workspace files.

### Affected `memory/` directory state

Before fix — files in workspace `memory/` directory after the bug appeared on 2026-04-15 are only the daily files written by the agent itself (via the `edit`/`write` tools when `workspaceOnly: false`), no `session-memory`-hook outputs. Last successful hook output: 2026-04-14.

---

RUN apt-get update && apt-get install -y \
    curl \
    python3 \
    && rm -rf /var/lib/apt/lists/*
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

writeFileWithinRoot and openFileWithinRoot in dist/fs-safe-*.js require python3 to be available in PATH because they spawn a Python subprocess for atomic file writes (using os.open with O_NOFOLLOW, dir_fd-based path walking, and os.replace). When python3 is missing — which is the default in node:24-bookworm-slim and similar slim Docker base images — the underlying error (spawn python3 ENOENT) is swallowed by normalizePinnedWriteError and surfaces as the misleading message: path is not a regular file under root This breaks several real user-facing features:

The bundled session-memory hook never writes session summaries to memory/ on /new or /reset. Agents with tools.fs.workspaceOnly: true cannot use edit, write, or apply_patch — even on files that are clearly inside their workspace. Any other code path that calls writeFileWithinRoot or openFileWithinRoot fails identically.

The misleading error message strongly suggests a path/permission/symlink problem, leading users (and AI agents debugging this) down hours of dead-end investigation. There is also no mention of python3 as a requirement in the official Docker installation docs.

Steps to reproduce

Build a minimal OpenClaw Docker image based on node:lts-bookworm-slim (which does not ship python3):

dockerfile FROM node:lts-bookworm-slim RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* RUN npm install -g openclaw@latest USER node WORKDIR /home/node/.openclaw/workspace CMD ["sh", "-c", "openclaw gateway"]

Start the container, complete onboarding, send a message, then issue /new to trigger the session-memory hook. Observe in docker logs:

[hooks/session-memory] Failed to save session memory

No new file appears in ~/.openclaw/workspace/memory/. Reproduce directly to see the underlying cause:

bash docker exec -u node <container> node --input-type=module -e ' import { g as writeFileWithinRoot } from "/usr/local/lib/node_modules/openclaw/dist/fs-safe-CtRwwu0C.js"; try { await writeFileWithinRoot({ rootDir: "/home/node/.openclaw/workspace/memory", relativePath: "__test.md", data: "test\n", encoding: "utf-8" }); console.log("OK"); } catch (e) { console.log("FAIL message:", e.message); console.log("FAIL cause:", e.cause); } ' Output: FAIL message: path is not a regular file under root FAIL cause: Error: spawn python3 ENOENT errno: -2, code: 'ENOENT', syscall: 'spawn python3', path: 'python3'

Install python3 and re-run — the same call now succeeds and the file is written.

Expected behavior

Either:

A) fs-safe does not depend on a Python subprocess — atomic writes are implemented in pure Node (preferred), or B) If the Python helper is required, the runtime dependency is documented prominently in the Docker installation guide, and a missing python3 produces a clear, actionable error message instead of "path is not a regular file under root".

The current behavior conflates a host environment problem (missing interpreter) with a path/permission problem (the message text), which is actively misleading.

Actual behavior

Actual behavior writeFileWithinRoot / openFileWithinRoot fail with: SafeOpenError: path is not a regular file under root at normalizePinnedWriteError (file:///.../fs-safe-.js:954:9) at file:///.../fs-safe-.js:779:9 at process.processTicksAndRejections (node:internal/process/task_queues:104:5) at async writeFileWithinRoot (file:///.../fs-safe-*.js:767:19) The real cause (spawn python3 ENOENT) is attached to the error object but is not logged anywhere by the consumers of this API:

The session-memory hook calls log.error("Failed to save session memory", { errorName, errorMessage, stack }) — the cause chain is dropped. Tool invocations of edit / write show only the normalized headline.

So unless a user manually calls writeFileWithinRoot and inspects e.cause, the real problem is invisible.

OpenClaw version

Auf: 2026.4.23 (currently running). Also confirmed on 2026.4.10 host install — but in 2026.4.10 my host had python3 installed, so I cannot say if 2026.4.10 in a python3-less container would also fail.

Operating system

Container: Debian 12 (bookworm-slim) on Linux x86_64 host

Install method

Docker base image: node:lts-bookworm-slim

Model

not applicable

Provider / routing chain

not applicable

Additional provider/model setup details

No response

Logs, screenshots, and evidence

### Reproduction output

Direct call to `writeFileWithinRoot` from a fresh `node:lts-bookworm-slim` container without `python3`:
FAIL message: path is not a regular file under root
FAIL cause: Error: spawn python3 ENOENT
at ChildProcess._handle.onexit (node:internal/child_process:287:19)
at onErrorNT (node:internal/child_process:508:16)
at process.processTicksAndRejections (node:internal/process/task_queues:90:21) {
errno: -2,
code: 'ENOENT',
syscall: 'spawn python3',
path: 'python3',
spawnargs: [ '-c', '<python helper script for atomic O_NOFOLLOW write>', ... ]
}
FAIL stack: SafeOpenError: path is not a regular file under root
at normalizePinnedWriteError (file:///usr/local/lib/node_modules/openclaw/dist/fs-safe-CtRwwu0C.js:954:9)
at file:///usr/local/lib/node_modules/openclaw/dist/fs-safe-CtRwwu0C.js:779:9
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
at async writeFileWithinRoot (file:///usr/local/lib/node_modules/openclaw/dist/fs-safe-CtRwwu0C.js:767:19)

### Gateway log when `session-memory` hook fires (e.g. on `/new`)

Only the headline is logged; the real cause is dropped:
2026-04-26T18:50:44.021+02:00 [hooks/session-memory] Failed to save session memory
2026-04-26T20:01:08.348+02:00 [hooks/session-memory] Failed to save session memory

### Verification after installing `python3`

After `apt-get install -y python3` in the same container, the same call succeeds:
$ docker exec -u node openclaw node --input-type=module -e '...'
OK undefined

The `session-memory` hook now writes files to `~/.openclaw/workspace/memory/` again on `/new`, and `tools.fs.workspaceOnly: true` no longer blocks `edit` / `write` on in-workspace files.

### Affected `memory/` directory state

Before fix — files in workspace `memory/` directory after the bug appeared on 2026-04-15 are only the daily files written by the agent itself (via the `edit`/`write` tools when `workspaceOnly: false`), no `session-memory`-hook outputs. Last successful hook output: 2026-04-14.

Impact and severity

Affected users/systems

  • Anyone running OpenClaw in a Docker container based on a slim image without python3 (notably node:*-slim, which is the recommended base for production deployments).
  • All code paths that go through writeFileWithinRoot / openFileWithinRoot in dist/fs-safe-*.js. Confirmed affected:
    • The bundled session-memory hook (silently fails on every /new and /reset).
    • Agent file tools edit, write, apply_patch when tools.fs.workspaceOnly: true is set.
  • Independent of channel (Telegram, WebChat, etc.), independent of model/provider.

Severity

Blocks workflow + silent data loss.

  • Silent data loss: the session-memory hook is enabled by default. Users who rely on automatic session summaries lose every single one with no visible failure to the user — only a one-line log entry in the gateway log.
  • Blocks workflow: users who set workspaceOnly: true for security/sandboxing cannot use edit / write at all, even on files clearly inside the workspace. The misleading error message ("path is not a regular file under root") sends users investigating path/symlink/permission issues that are not the actual cause.

Frequency

Always. 100% reproducible on any container without python3 in PATH. Every single /new triggers the failure; every single edit with workspaceOnly: true triggers the failure.

Consequence

  • Session continuity is broken (no # Session: ... summaries written to memory/ for the affected period).
  • The workspaceOnly: true security setting is effectively unusable in slim Docker images, forcing users to run with workspaceOnly: false (broader filesystem access) just to make edit/write work.
  • Significant debugging time wasted by users (and AI agents debugging on their behalf) chasing the misleading error message. Personal experience: ~1 day of investigation across multiple sessions before the real cause surfaced, because the error text actively suggests the wrong problem class.

Additional information

Regression timeline

Cannot be determined from available evidence.

I observed the bug starting after migrating from a host install (where python3 happened to be installed) to a Docker container based on node:lts-bookworm-slim (which does not include python3). The bug coincided with my Docker migration in my environment, but I cannot say from this whether the python3 dependency in fs-safe was newly introduced at some point or has always existed. A maintainer with access to the version history of dist/fs-safe-*.js could determine when the Python helper was added.

Last observed working version in my setup: 2026.4.10 (host install with python3 available). First observed broken version in my setup: 2026.4.15 (Docker without python3).

These two data points do not isolate a regression — only that the bug is reachable in this environment combination.

Why the misdiagnosis is hard to escape from

The headline error message ("path is not a regular file under root") contains the words path, regular file, under root — all of which suggest filesystem/permission/symlink issues. The actual cause (spawn python3 ENOENT) is attached as e.cause but is not logged anywhere by the consumers of writeFileWithinRoot. To find it, a user must:

  1. Suspect the issue is not really about paths.
  2. Manually call writeFileWithinRoot from the Node REPL with try/catch.
  3. Inspect e.cause (not e.message or e.stack).

This is not a typical debug path. The fix recommendations (preserve cause chain in normalizePinnedWriteError, add a doctor check, document python3 as a runtime dep) would each independently prevent this debug pattern.

Related issues

  • #40334 — Different bug in the same writeFileWithinRoot function (workspaceOnly: false ignored after gateway restart). Suggests this function has had multiple issues and would benefit from review.
  • #22793 — Same misdiagnosis pattern (spawn /bin/sh ENOENT misleadingly points at the shell binary rather than the real cause: missing cwd). Indicates a broader codebase pattern of hiding spawn ENOENT causes behind unrelated error messages.

Workaround for affected users

Add python3 to the apt-get install list in the Dockerfile:

RUN apt-get update && apt-get install -y \
    curl \
    python3 \
    && rm -rf /var/lib/apt/lists/*

After rebuild, both the session-memory hook and workspaceOnly: true work correctly.

extent analysis

TL;DR

Install python3 in the Docker container by adding it to the apt-get install list to resolve the spawn python3 ENOENT error.

Guidance

  • The error message "path is not a regular file under root" is misleading and actually indicates a missing python3 dependency.
  • To fix the issue, add python3 to the Dockerfile's apt-get install list.
  • Verify the fix by checking if the session-memory hook writes files to the memory/ directory and if edit/write tools work with workspaceOnly: true.
  • Consider preserving the cause chain in normalizePinnedWriteError to prevent similar misdiagnosis in the future.

Example

RUN apt-get update && apt-get install -y \
    curl \
    python3 \
    && rm -rf /var/lib/apt/lists/*

Notes

The python3 dependency is not documented in the official Docker installation guide, leading to confusion when the error occurs. Installing python3 resolves the issue, but it's essential to address the root cause and improve error handling to prevent similar problems.

Recommendation

Apply the workaround by installing python3 in the Docker container, as it is a required dependency for the writeFileWithinRoot and openFileWithinRoot functions.

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…

FAQ

Expected behavior

Either:

A) fs-safe does not depend on a Python subprocess — atomic writes are implemented in pure Node (preferred), or B) If the Python helper is required, the runtime dependency is documented prominently in the Docker installation guide, and a missing python3 produces a clear, actionable error message instead of "path is not a regular file under root".

The current behavior conflates a host environment problem (missing interpreter) with a path/permission problem (the message text), which is actively misleading.

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 - ✅(Solved) Fix [Bug]: `fs-safe` writes silently fail in Docker with misleading "path is not a regular file under root" when `python3` is not in PATH [1 pull requests, 1 participants]