[BUG] Filesystem write_file tool does not preserve file permissions

Resolved 💬 5 comments Opened Apr 12, 2026 by smartwatermelon Closed May 23, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Summary

The Filesystem:write_file tool resets file permissions to a default (likely 644) when writing, even when overwriting an existing file that has non-default permissions set. This causes silent breakage when the tool is used to update executable scripts.

Permissions are reset to 644 on every write, stripping the execute bit. The file is silently non-executable.

Impact

  • Shell scripts updated via write_file silently lose their execute bit
  • The failure mode is downstream and non-obvious: the script exists, the content is correct, but it won't run
  • In this specific case: ~/Developer/claude-wrapper/bin/claude-wrapper (a symlink target) had +x stripped, causing claude (which symlinks to it) to fail silently on the next invocation
  • This has caused repeated debugging sessions across multiple conversations

What Should Happen?

write_file should preserve the existing file's permission bits when overwriting. If no prior file exists, 644 is a reasonable default.

Error Messages/Logs

Steps to Reproduce

  1. Create an executable script:

``bash
echo '#!/usr/bin/env bash\necho hello' > ~/test.sh
chmod +x ~/test.sh
ls -l ~/test.sh # -rwxr-xr-x
``

  1. Use Filesystem:write_file to update the file content
  2. Check permissions:

``bash
ls -l ~/test.sh # -rw-r--r-- — execute bit gone
``

Claude Model

Sonnet (default)

Is this a regression?

No, this never worked

Last Working Version

_No response_

Claude Code Version

2.1.104

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

iTerm2

Additional Information

Suggested Fix

Before writing, stat the existing file and restore its permission bits after the write:

import os, stat
existing_perms = stat.S_IMODE(os.stat(path).st_mode) if os.path.exists(path) else 0o644
# ... write file ...
os.chmod(path, existing_perms)

Or alternatively, expose an optional permissions parameter so callers can explicitly set mode bits when they know the file should be executable.

View original on GitHub ↗

This issue has 5 comments on GitHub. Read the full discussion on GitHub ↗