openclaw - ✅(Solved) Fix Edit tool silently wipes file to 0 bytes while reporting success [2 pull requests, 11 comments, 6 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#43858Fetched 2026-04-08 00:18:30
View on GitHub
Comments
11
Participants
6
Timeline
28
Reactions
0
Author
Timeline (top)
commented ×11mentioned ×6subscribed ×6cross-referenced ×4

Error Message

The edit parameters used both old_string/new_string and file_path. The old_string values were multi-line blocks that existed verbatim in the files. The match was correct (first call on MEMORY.md reported success before the file was found empty). This is not a "text not found" error — the tool confirmed the match but destroyed the file content during the write-back.

Fix Action

Workaround

Using sed -i via the exec tool instead of the Edit tool for file modifications.

PR fix notes

PR #43921: fix(sandbox): guard against empty-stdin file overwrites in run_write

Description (problem / solution / changelog)

What

Defense-in-depth guard in the sandbox Python run_write helper: refuse to os.replace when the temp file is 0 bytes and the target already exists.

Why

Fixes #43858 — the edit tool silently wipes files to 0 bytes while reporting success.

The root cause (heredoc consuming stdin) was fixed in #43876, but a broken pipe or abort race could still deliver 0 bytes to write_stdin_to_fd. Without this guard, run_write atomically replaces the target with an empty temp file, destroying content.

How

After write_stdin_to_fd(temp_fd), check os.fstat(temp_fd).st_size. If 0 and the target file exists, raise RuntimeError and clean up the temp file. Creating new empty files is still allowed.

Testing

  • pnpm test src/agents/sandbox/ — 116/116 passed
  • AI-assisted (Claude, fully tested)

Changed files

  • src/agents/sandbox/fs-bridge-mutation-helper.ts (modified, +10/-0)
  • src/agents/sandbox/fs-bridge-mutation-python-source.ts (modified, +13/-0)

PR #39715: fix: drain stdout/stderr before resolving child wait

Description (problem / solution / changelog)

Summary

Fixes #30711 — stdout lost when a backgrounded sandbox process produces block-buffered output that is only flushed at exit.

  • When a sandboxed process (e.g. bun on a pipe inside Docker) uses block-buffered stdout, all output is flushed at exit. The child close event and the final stdout data event can land in the same libuv poll cycle, causing the promise microtask chain to snapshot session.aggregated before the data callback runs — silently losing the output.
  • Added a setImmediate yield in the child adapter's wait() after the close event resolves, ensuring pending I/O callbacks (stdout/stderr data events) are processed before the promise chain continues.
  • Added a second setImmediate yield in the supervisor before calling adapter.dispose(), as a safety net for data callbacks enqueued between the adapter yield and the supervisor's snapshot.

Changes

FileChange
src/process/supervisor/adapters/child.tssetImmediate yield after child.once("close") resolves
src/process/supervisor/supervisor.tssetImmediate yield before adapter.dispose()
src/agents/bash-tools.exec.background-stdout.test.ts3 regression tests

Test plan

  • New test: backgrounded process stdout captured when output flushed at exit
  • New test: backgrounded process captures both stdout and stderr
  • New test: large block-buffered output captured correctly
  • All 44 existing exec tests pass (no regression)
  • All 24 supervisor tests pass
  • All 5 process registry tests pass
  • All 10 process tool tests pass
  • Manual: run a bun/node command that takes >10s in sandbox, verify process log shows output without 2>&1

🤖 Generated with Claude Code

Changed files

  • src/agents/bash-tools.exec.background-stdout.test.ts (added, +98/-0)
  • src/process/supervisor/supervisor.test.ts (modified, +25/-0)
  • src/process/supervisor/supervisor.ts (modified, +27/-10)
RAW_BUFFERClick to expand / collapse

Bug Description

The Edit (file edit / replace exact text) tool silently wipes the target file to 0 bytes while reporting "Successfully replaced text in <file>." The old text is found and matched correctly, but instead of performing an in-place replacement, the entire file content is lost.

Reproduction

Environment:

  • OpenClaw v2026.3.11 (29dc654)
  • Runtime: Docker sandbox (arm64, Linux 6.17.8-orbstack)
  • Model: anthropic/claude-opus-4-6

Steps:

  1. Have a file with known content (e.g., MEMORY.md, 141 lines)
  2. Use the Edit tool with a valid old_string / new_string pair that matches content in the file
  3. Tool returns: "Successfully replaced text in MEMORY.md."
  4. File is now 0 bytes

Observed behavior:

  • This happened twice in succession on two different files (MEMORY.md and TOOLS.md) in the same session
  • Both times the tool reported success
  • Both files were reduced to 0 bytes
  • Recovery was done via git checkout

Expected behavior:

  • The matched text should be replaced in-place; the rest of the file should be preserved

Workaround

Using sed -i via the exec tool instead of the Edit tool for file modifications.

Additional Context

The edit parameters used both old_string/new_string and file_path. The old_string values were multi-line blocks that existed verbatim in the files. The match was correct (first call on MEMORY.md reported success before the file was found empty). This is not a "text not found" error — the tool confirmed the match but destroyed the file content during the write-back.

extent analysis

Fix Summary

The Edit tool opens the target file in write‑truncate mode before it has read the original contents, so when the replacement logic runs the file is already empty.
Fix it by:

  1. Read the whole file first (or stream it line‑by‑line).
  2. Perform the string replacement in memory.
  3. Write back atomically (write to a temporary file, then rename).
  4. Add safety checks (backup, encoding, size limits) and unit tests.

Below is a minimal, production‑ready implementation in Python (the language used by the OpenClaw tool‑chain). Adjust paths if your tool is written in another language.


Step‑by‑Step Fix Plan

1. Update the Edit‑tool implementation

# edit_tool.py  (simplified)
import os
import shutil
import tempfile
from pathlib import Path

def edit_file(file_path: str, old_string: str, new_string: str) -> str:
    """
    Replace `old_string` with `new_string` inside `file_path`.
    Returns a human‑readable status message.
    """
    path = Path(file_path)

    if not path.is_file():
        return f"❌ File not found: {file_path}"

    # -------------------------------------------------
    # 1️⃣  Read the original content *before* touching the file
    # -------------------------------------------------
    try:
        # Preserve original encoding (default to utf‑8)
        raw = path.read_bytes()
        encoding = "utf-8"
        try:
            text = raw.decode(encoding)
        except UnicodeDecodeError:
            # fallback – let Python guess
            text = raw.decode(errors="replace")
    except Exception as exc:
        return f"❌ Could not read {file_path}: {exc}"

    # -------------------------------------------------
    # 2️⃣  Verify the old string exists
    # -------------------------------------------------
    if old_string not in text:
        return f"⚠️ Text not found in {file_path}. No changes made."

    # -------------------------------------------------
    # 3️⃣  Perform the replacement in memory
    # -------------------------------------------------
    new_text = text.replace(old_string, new_string, 1)   # replace first occurrence

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