[BUG] Task-output read errors always claim "another Claude Code process ... deleted it during startup cleanup" — fixed string appended to every read failure, misdirecting debugging
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?
When a Bash task's output file cannot be read, Claude Code appends a fixed sentence to the error:
This usually means another Claude Code process in the same project deleted it during startup cleanup.
The sentence is appended unconditionally, on every read failure, regardless of the error code — ENOENT, EACCES, EIO, anything — and without checking any evidence that such a process existed or acted. It is a hard-coded guess rendered as a diagnosis.
The read-side handler in the shipped bundle (2.1.241, decompiled excerpt; identifiers are minified):
catch(t){ let r = t instanceof Error && "code" in t ? String(t.code) : "unknown";
return `<bash output unavailable: output file ${this.path} could not be read (${r}). ` +
"This usually means another Claude Code process in the same project deleted it during startup cleanup.>" }
Two properties:
- Unconditional on the error.
${r}interpolates whatever code the failure carried; the "startup cleanup" sentence is identical in every case. A permission failure gets "explained" as a peer deletion. - No evidence is consulted. Nothing checks whether another Claude Code process ran, whether a startup occurred in the window, or whether the configured retention (
cleanupPeriodDays) even permits deletion. On the machine where this was measured, retention was set to 9999 days — making the named mechanism impossible — and the message asserted it anyway, verbatim, 24 times.
Why this matters
The message converts a generic I/O failure into a confident, specific, usually-unverifiable accusation, and it misdirects debugging at scale:
- In a measured incident (24 emissions over 6 days), the real deleter was a local test script sweeping
/tmp— but "the CLI already told us what happened" sent the investigation toward Claude Code's startup path for days, including a full bundle decode hunting for a peer-cleanup deleter that (with retention disabled) does not exist. - The same happens for every user who hits an unreadable task-output file for any other reason: tmpwatch/tmpreaper, containers with ephemeral
/tmp, antivirus, disk faults. Issue threads show users repeating the message's diagnosis as established fact. - The wording appears to be a fossil: #42536 (April 2026) describes an era when sessions genuinely did delete each other's output files during startup cleanup, before session-id namespacing of the task dirs. The collision was fixed; the accusatory message survived.
An error message is load-bearing diagnostic surface. A wrong-but-confident one is worse than none.
What Should Happen?
State the fact and the error code; drop or genuinely hedge the causal assertion. Smallest change:
<bash output unavailable: output file <path> could not be read (ENOENT).>
optionally followed by a hedged hint gated on the error code:
Possible causes: the file was removed by an external tmp cleaner, another process, or (if retention cleanup is enabled) Claude Code's own startup cleanup.
Verifying the cause before asserting it (check for a recent peer startup; honor cleanupPeriodDays) would be strictly better but is more code than a message needs.
Steps to Reproduce
Executed 2026-08-24 against 2.1.241 (Linux/WSL2):
- In a running session, launch a background Bash task:
sleep 90 && echo done. - Delete its output file from the same session (or any external means) while the task runs:
rm -f $TMPDIR/claude-<uid>/<project-slug>/<session-id>/tasks/<task-id>.output
- Request the task's output while the task is still running.
Expected: an error stating the file could not be read (ENOENT).
Actual (observed verbatim; project/session path segments elided):
<bash output unavailable: output file /tmp/.../claude-1000/<project-slug>/<session-id>/tasks/ba31blud3.output could not be read (ENOENT). This usually means another Claude Code process in the same project deleted it during startup cleanup.>
No other Claude Code process touched the file — the deleter was the same session's own rm, one tool call earlier — and the message asserted the peer-startup cause anyway.
Timing note for anyone reproducing: the harness's exit-time append recreates the output file, so deleting it after completion self-heals. The message fires when the file is read while missing — a mid-run read, or the containing directory removed (the common external-cleaner shape).
Prior art (context, not duplicates)
- #42536 → closed as duplicate of #32252 (itself closed NOT_PLANNED/stale, never triaged) — describes the pre-namespacing era when the message's claim was true.
- #75354 — the retention/cleanup design discussion; adjacent, but about cleanup behavior, not the message.
- #86222 — a different defect (persistent EACCES on the task dir) whose reporters also received misleading messaging.
None of these asks for the message itself to be fixed; this report is only about the message.
Environment
- Claude Code 2.1.241
- Linux (WSL2),
cleanupPeriodDays: 9999