[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

Status Open
Reported on v2.1.241
Maintainer reply None cached
Activity 0 comments · opened Aug 24, 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?

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 codeENOENT, 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:

  1. 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.
  2. 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):

  1. In a running session, launch a background Bash task: sleep 90 && echo done.
  2. 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

  1. 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

View original on GitHub ↗