claude-code - 💡(How to fix) Fix [BUG] Edit tool silently fails (reports success, no write) when target is a relative `..` symlink inside a symlinked-directory chain [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
anthropics/claude-code#52463Fetched 2026-04-24 06:06:34
View on GitHub
Comments
0
Participants
1
Timeline
4
Reactions
0
Participants
Timeline (top)
labeled ×4

Edit returns "The file ... has been updated successfully." but the target file on disk is unchanged when the path satisfies all of:

  1. The directory portion traverses one or more symlinked directories, and
  2. The leaf path component is itself a symbolic link, and
  3. The leaf symlink's target is a relative path containing .. (e.g. ../settings.json).

Removing any one of these conditions → write persists correctly (bisect below). This is a silent correctness bug: no error, no warning, no tmp file left behind, the write goes nowhere. The symlink on disk is not replaced with a regular file (distinguishing this from #28376 / worktree-related #40857).

Error Message

Removing any one of these conditions → write persists correctly (bisect below). This is a silent correctness bug: no error, no warning, no tmp file left behind, the write goes nowhere. The symlink on disk is not replaced with a regular file (distinguishing this from #28376 / worktree-related #40857). Either persist the write through to the resolved real file, or return an error. Alternatively, the tool may detect the configuration and bail without surfacing an error.

Root Cause

  • #28376 (closed/stale) — Write/Edit replaces a symlink with a regular file. Different symptom: there the target file never updates and the symlink is destroyed; here the symlink is preserved and the write lands nowhere observable.
  • #40857symlinkDirectories worktrees: write replaces symlink with regular file. Similar shape to #28376, worktree-scoped.
  • #44035 — Claude Code reports successful writes / git commits that never happen. Different root cause (long-running Ralph-Loop session, possibly no tool call emitted); our bug is a single-Edit, 30-second deterministic repro.
  • #51214 — Desktop app: Write/Edit silently fails to flush mid-session. Platform differs (Desktop, post-rewrite 1.3109).
  • #4462 — Sub-agents claim successful file creation that doesn't persist. Sub-agent scoped.
  • #764 — Symlink resolution failure traversing symlinked dirs. Older, about Read/traversal.

Fix Action

Fix / Workaround

Workarounds

Code Example

R=$(mktemp -d -t claude-symlink-bug)
mkdir -p "$R/real/host"
echo '{"k":"v1"}' > "$R/real/settings.json"
ln -s ../settings.json "$R/real/host/settings.json"   # leaf symlink, relative parent target
ln -s real/host        "$R/synced"                     # dir symlink
ln -s synced           "$R/dot"                        # dir symlink
echo "Edit this path: $R/dot/settings.json"

---

cat "$R/real/settings.json"         # still {"k":"v1"}
   ls -la "$R/real/host/settings.json" # still a symlink, not replaced
RAW_BUFFERClick to expand / collapse

Summary

Edit returns "The file ... has been updated successfully." but the target file on disk is unchanged when the path satisfies all of:

  1. The directory portion traverses one or more symlinked directories, and
  2. The leaf path component is itself a symbolic link, and
  3. The leaf symlink's target is a relative path containing .. (e.g. ../settings.json).

Removing any one of these conditions → write persists correctly (bisect below). This is a silent correctness bug: no error, no warning, no tmp file left behind, the write goes nowhere. The symlink on disk is not replaced with a regular file (distinguishing this from #28376 / worktree-related #40857).

What Should Happen

Either persist the write through to the resolved real file, or return an error.

Steps to Reproduce

Build the minimal layout in a shell:

R=$(mktemp -d -t claude-symlink-bug)
mkdir -p "$R/real/host"
echo '{"k":"v1"}' > "$R/real/settings.json"
ln -s ../settings.json "$R/real/host/settings.json"   # leaf symlink, relative parent target
ln -s real/host        "$R/synced"                     # dir symlink
ln -s synced           "$R/dot"                        # dir symlink
echo "Edit this path: $R/dot/settings.json"

In a Claude Code session:

  1. Read$R/dot/settings.json. Content: {"k":"v1"}.
  2. Edit the same path, old_string="{\"k\":\"v1\"}", new_string="{\"k\":\"v2\"}".
  3. Edit returns: "The file ... has been updated successfully."
  4. Back in the shell:
    cat "$R/real/settings.json"         # still {"k":"v1"}
    ls -la "$R/real/host/settings.json" # still a symlink, not replaced

Bisect

Six configurations tested on v2.1.118 / macOS 26.3 (Darwin 25.3, arm64) / APFS. Only the one matching the real failing layout silently fails:

#Dir-symlink chainLeaf is symlinkLeaf targetEdit persists?
1noyessibling in same dir
2yesyes../foo.json (parent-relative)✗ silent success, no write
3noyes../foo.json (parent-relative)
Ayesno (real file at leaf)
Byesyessibling in same dir
Cyesyesabsolute path

Trigger is specifically relative .. in the leaf symlink target combined with a symlinked-directory chain on the access path. Either alone is safe; the combination is not.

Likely Cause (speculation)

The leaf symlink's relative target appears to be resolved against the virtual (symlink-walked) path rather than against the symlink's actual on-disk containing directory. With the access path $R/dot/settings.json, the leaf's ../settings.json should resolve to $R/real/settings.json (relative to $R/real/host/, where the symlink lives); instead the write seems to target something that doesn't exist or is silently discarded.

Alternatively, the tool may detect the configuration and bail without surfacing an error.

Impact

Silent data loss for shared-config layouts that use symlinked directories with relative-up leaf symlinks — a common pattern for dotfile managers and multi-machine sync setups. Specifically bit a user trying to sync ~/.claude/ across two Macs via iCloud: ~/.claude → .claude-synced → .claude-home/<hostname>/ (two dir symlinks) and settings.json → ../settings.json inside the hostname dir (leaf symlink, relative up) — exactly config #2. Settings edits appeared successful in-session and the sync architecture had to be abandoned after the silent failures were diagnosed by byte-comparing backups against post-Edit state.

Related Issues (not duplicates)

  • #28376 (closed/stale) — Write/Edit replaces a symlink with a regular file. Different symptom: there the target file never updates and the symlink is destroyed; here the symlink is preserved and the write lands nowhere observable.
  • #40857symlinkDirectories worktrees: write replaces symlink with regular file. Similar shape to #28376, worktree-scoped.
  • #44035 — Claude Code reports successful writes / git commits that never happen. Different root cause (long-running Ralph-Loop session, possibly no tool call emitted); our bug is a single-Edit, 30-second deterministic repro.
  • #51214 — Desktop app: Write/Edit silently fails to flush mid-session. Platform differs (Desktop, post-rewrite 1.3109).
  • #4462 — Sub-agents claim successful file creation that doesn't persist. Sub-agent scoped.
  • #764 — Symlink resolution failure traversing symlinked dirs. Older, about Read/traversal.

Workarounds

  • Target the resolved real path directly (readlink -f), bypassing the symlink chain.
  • Use Bash to write (python3 -c "open(p,'w').write(s)", sed -i, etc.) — these follow symlinks normally.
  • Restructure the layout to avoid relative .. in leaf symlinks: use absolute targets (config C works), or keep the leaf as a real file inside a symlinked directory (config A works).

Environment

  • Claude Code version: 2.1.118
  • API platform: Anthropic API
  • OS: macOS 26.3.1 (Darwin 25.3.0, arm64)
  • Terminal: Terminal.app
  • Filesystem: APFS
  • Regression: unknown — observed on 2.1.116 (prior session) and 2.1.118 (current); earlier versions not tested.

extent analysis

TL;DR

The issue can be resolved by targeting the resolved real path directly or restructuring the layout to avoid relative .. in leaf symlinks.

Guidance

  • Identify and avoid using relative .. in leaf symlinks within symlinked directories to prevent silent data loss.
  • Use readlink -f to resolve the real path and target it directly for writes.
  • Consider restructuring the layout to use absolute targets in symlinks or keeping the leaf as a real file inside a symlinked directory.
  • As a temporary workaround, use Bash to write files, which follows symlinks normally.

Example

No code snippet is provided as the issue is related to the interaction between the Claude Code tool and the file system, rather than a specific code snippet.

Notes

The exact cause of the issue is speculative, but it appears to be related to how the tool resolves the leaf symlink's relative target. The provided workarounds and restructuring suggestions should help mitigate the issue.

Recommendation

Apply a workaround, such as targeting the resolved real path directly or restructuring the layout, as the root cause of the issue is not clearly identified and may require further investigation.

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

claude-code - 💡(How to fix) Fix [BUG] Edit tool silently fails (reports success, no write) when target is a relative `..` symlink inside a symlinked-directory chain [1 participants]