[BUG] Sonnet writes scratch files to the filesystem root (`/tmp_err_c.txt`) when /tmp, $TMPDIR and the session scratchpad all exist
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?
The model composed a Bash command that writes scratch files directly under the filesystem root:
2>/tmp_err_c.txt2>/tmp_err_l.txt
It then ended the command with rm -f /tmp_err_c.txt /tmp_err_l.txt.
The path looks like a typo for /tmp/err_c.txt. The model never wrote a directory separator after tmp. The result is a file at /, not in a temp directory.
Claude Code's built-in dangerous-rm check then denied the command, because the rm target sits at the root. The command never ran.
The defect is the write location, not the denial. The denial behaved correctly. A removal at the filesystem root should need a person's approval.
Better locations existed and were known to the session:
/tmp/, or$TMPDIRmktemp- the per-session scratchpad directory
- no file at all, because the command needed none
The model itself identified the scratchpad as the right place. After the denial it wrote:
The safety check blocked my cleanup path (/tmp_err_c.txt at the filesystem root, a sloppy choice on my part). Nothing ran. I'm re-running with scratchpad temp files and no rm.
So the correct location was available the whole time. The first attempt did not use it.
Why this matters beyond one wasted turn:
- A write at
/can fail on a permissions error, or succeed on a system that allows it. On a system that allows it, the file lands outside every project and outside any cleanup. - The
rmcannot run without a person present. In auto mode and in unattended runs, no person is present. The model therefore cannot clean up the file it created. - Each denial costs a full retry turn, and the task stops until the model re-plans.
What Should Happen?
Any of these would help, in order of preference:
- The model should never choose a root-level path for a scratch file. It should use the session scratchpad when one is provided. Otherwise it should use
$TMPDIR,/tmp/…ormktemp. - The model should skip the temp file when none is needed. This loop could capture each error in a shell variable with
err=$(cmd 2>&1 >/dev/null). That needs no file and no cleanup. - The harness could flag a redirect to a root-level path the same way it flags an
rmthere. This catches the write before the model plans a cleanup it cannot run. - The system prompt could state the scratch-file rule more directly. Name the location, and say a path directly under
/is never a temp location.
Error Messages/Logs
Command (abridged, loop body only):
for pair in 79:545 80:546 ... 102:563; do
n=${pair%%:*}; bb=${pair##*:}
if gh issue comment $n -R <owner>/<repo> --body "..." >/dev/null 2>/tmp_err_c.txt; then c=ok
else c="PENDING: $(head -c 150 /tmp_err_c.txt)"; fi
if gh issue edit $n -R <owner>/<repo> --add-label intake >/dev/null 2>/tmp_err_l.txt; then l=ok
else l="PENDING: $(head -c 150 /tmp_err_l.txt)"; fi
echo "#$n BB-$bb comment=$c label=$l"
done
rm -f /tmp_err_c.txt /tmp_err_l.txt
Result:
Error: Permission for this command was denied by a built-in Claude Code safety check,
not by the user. The check stops removals that can delete far more than intended: a
system, home or workspace directory, or a target it cannot resolve ...
What was flagged: Dangerous rm operation detected: '/tmp_err_c.txt'
This command would remove a critical system directory. This requires explicit approval
and cannot be auto-allowed by permission rules.
Model's reply after the denial:
The safety check blocked my cleanup path (/tmp_err_c.txt at the filesystem root, a sloppy
choice on my part). Nothing ran. I'm re-running with scratchpad temp files and no rm.
Steps to Reproduce
I do not have a deterministic repro. This is a model-behavior report from one captured turn. These are the conditions:
- Run Sonnet 5.5 at high effort.
- Give it a task that loops over many items and calls a CLI per item, such as
gh issue commentover about 19 issues. - The task needs per-item error text on failure, so the model reaches for
2>fileand a laterhead -cof that file. - The model writes the redirect target as
/tmp_err_c.txt, with no separator. - The dangerous-
rmcheck denies the cleanup line, and the whole command is blocked.
→ confirm how often this recurs. I have one captured instance.
Claude Model
Sonnet (default)
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.296
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
PowerShell
Additional Information
Where the denial sits relative to the defect
| Step | What happened | Correct? |
|---|---|---|
| Model picks /tmp_err_c.txt as a scratch path | Root-level path chosen | No — this is the defect |
| Model appends rm -f on that path | Cleanup planned for a root-level file | No — follows from the first step |
| Safety check flags the rm | Denied, command not run | Yes — the check worked |
| Model acknowledges the error and switches to scratchpad files | Self-corrected | Yes — but one turn late |
A fix aimed at the safety check would be the wrong fix. The check blocked a root-level removal as designed.
Related issues
| Issue | State | Relationship |
|---|---|---|
| #100630 | open | Covers how the dangerous-rm check classifies path spellings. It does not cover where the model chooses to write. |
| #96300 | closed | Covers the same check not looking inside sh -c. It does not cover the write location. |
Limits of this report
- One captured instance. I cannot give a rate.
- The write never happened. The denial blocked the whole command before any redirect ran. I have not shown that a redirect to
/tmp_err_c.txtsucceeds on this machine. - I do not know whether this session had a scratchpad directory listed in its system prompt. The model's own reply says it did.
- I did not test other effort levels or models.