How a Background Task Ate 324 GB of Disk Space

A background task in Claude Code silently grew a single .output file to 324 GB in 16 minutes on my Mac. I went through the session logs to understand why. Turns out others have seen up to 740 GB from the same unbounded output files.

Table of Contents

Claude Code has 3,617 open bugs . Today I ran into several of them at once.

Claude Code GitHub issue tracker filtered by open bugs
Figure 1. Claude Code open bugs in the GitHub issue tracker.

I asked Claude Code (v2.1.74) to review a research document I was working on. The prompt: “deeply check the research.md and address all the notes I left. Do additional research if needed and update the doc.”

It found 11 notes, launched 5 background research agents, and got to work. Then it tried to check on their progress. By the time I noticed something was wrong, a single .output file had consumed 324 GB on my Mac.

Finding the Damage

After the session, Disk Utility showed 21 GB free out of ~995 GB. That didn’t look right. I opened a new Claude Code session and asked it to help track down whatever was eating my storage. Standard suspects (home directory, Docker volumes, caches) all looked clean. Then I pointed it at the suspicious background task I had killed and asked it to check /private/tmp/:

$ du -sh /private/tmp/claude-501/
324G

Claude Code stores background task output in .output files under /private/tmp/claude-<uid>/<project-path>/tasks/. The base path is configurable via CLAUDE_CODE_TMPDIR.

$ du -sh .../tasks/*
324G    .../tasks/bday3zjvd.output          ← background bash task
  0B    .../tasks/ab82d716c855dd5ba.output  ← agent (completed normally)
  0B    .../tasks/a9bffb61f67ddceae.output
  0B    .../tasks/a4b988afd22aa8db1.output
  0B    .../tasks/a417efc2a4f409639.output
  0B    .../tasks/a2ded7593505f4524.output

A single file got all 324 GB. The 5 agent files were 0 bytes.

Claude Code handles bash tasks and agent tasks differently. For bash tasks, stdout and stderr go to the b*.output file with no size limit.

For agents, each subagent writes a JSONL (newline-delimited JSON) session log under ~/.claude/projects/, and the a*.output file is a symlink to it. When an agent finishes, Claude Code queues a task-notification message for the main session with the agent’s results. The agent files showed as 0 bytes, possibly because the symlink targets had been cleaned up by the time I checked.

A tail -5 loop can’t produce 324 GB of text. So what was writing to that file?

Reconstructing the Timeline

To find out, I compared timestamps from the main session log at ~/.claude/projects/<project-path>/<session-id>.jsonl against the subagent logs:

Reconstructed from session 462e8822-5f7d-428d-a444-33602f3b8a92

20:45:26  Claude Code launches 4 research agents
20:46:00  5th agent launched (GitHub milestones)
20:46:05  ls .../tasks/*.output → 6 files found (5 agents + bash task's own file)
20:46:10  Bash: for loop with tail -5 on each .output file
20:46:51  Agent a417efc completes (rig-core)        ← notification queued
20:47:17  Agent a9bffb6 completes (Coolify)         ← notification queued
20:47:23  Agent ab82d71 completes (GitHub images)   ← notification queued
20:47:25  Agent a4b988a completes (milestones)      ← notification queued
20:47:48  Agent a2ded75 completes (Telegram)        ← notification queued
          All 5 agents done. For loop also likely done.
          But the Bash process stays alive for 2 more minutes.
20:48:13  Bash command backgrounded → task bday3zjvd
          stdout: "", assistantAutoBackgrounded: false
          .output FILE GROWTH STARTS HERE (~340 MB/s)
20:48:16  Claude Code fetches TaskOutput tool via ToolSearch
20:48:19  TaskOutput(ab82d71) → "No task found"     ← 1 ms response
20:48:20  TaskOutput(a2ded75) → "No task found"     ← 1 ms response
20:48:21  TaskOutput(a9bffb6) → "No task found"     ← 1 ms response
20:48:22  TaskOutput(a417efc) → "No task found"     ← 1 ms response
20:48:22  TaskOutput(a4b988a) → "No task found"     ← 1 ms response
20:48:25  TaskOutput(bday3zjvd, block=true, timeout=10s)
20:48:35  TaskOutput returns: timeout, status: running, ~30K chars
20:49:17  "agents running into permission issues with web search...
          enough domain knowledge" → starts document rewrite
20:57:59  All 5 agent notifications dequeued simultaneously
          (~10 min delay: agents finished at 20:47, consumed at 20:58)
          Claude Code adds extra findings via targeted edits
21:04:23  I killed bday3zjvd → 324 GB over ~16 min of growth

The agents finish within 2 minutes. Each completion queues a task-notification, but those notifications don’t arrive for another 10 minutes, not until the model finishes the document rewrite.

The Innocent tail Command

After launching the agents, Claude Code runs a for loop with tail -5 on each .output file to check on their progress:

⏺ Bash(for f in /private/tmp/claude-501/.../tasks/*.output;
    do echo "=== $(basename $f) ==="; tail -5 "$f"; echo; done)

tail -5 reads the last 5 lines and exits. Without the -f flag, it doesn’t follow or wait for new data. A for loop over 6 files should finish in under a second. But the Bash process doesn’t return for 2 full minutes.

I don’t have a good explanation for this. It could be something in Claude Code’s bash execution wrapper, or stdout buffering between the shell process and the .output file. The timing roughly lines up with the agents finishing their work (the last one completes at 20:47:48), but I can’t draw a causal link.

Then Claude Code backgrounds the command as task bday3zjvd:

{
  "toolUseResult": {
    "stdout": "",
    "stderr": "",
    "backgroundTaskId": "bday3zjvd",
    "assistantAutoBackgrounded": false
  }
}

A command can be backgrounded in 3 ways:

  1. Claude Code passing run_in_background: true in the Bash tool call
  2. A user pressing Ctrl+B
  3. Automatic timeout. Since v2.0.19 , commands exceeding BASH_DEFAULT_TIMEOUT_MS ( default 120s ) are auto-backgrounded instead of killed

Claude Code didn’t request it (run_in_background was false). I didn’t press Ctrl+B. That leaves auto-timeout, and the ~2-minute runtime matches the 120s default exactly. The assistantAutoBackgrounded flag shows false, which appears to be a logging bug: the command was auto-backgrounded at the timeout, but the flag wasn’t set correctly.

Once backgrounded, Claude Code redirects stdout/stderr into the .output file. These files have no size limit, and are never cleaned up after sessions end .

Could the for loop be reading its own output file? The glob *.output expands in the same tasks/ directory where bday3zjvd.output is created. I reproduced the command in a fresh session: Claude Code creates the .output file before starting the bash process, so the glob does include it. tail -5 reads back its own earlier echo lines, roughly doubling the output. But it reads at most 5 lines and exits. The entire loop completes in under 30 milliseconds. Self-reference can’t explain 324 GB.

Before deleting the file, I checked the first 2000 bytes with head -c 2000. The beginning was normal: agent JSONL entries prefixed by === filename === headers from the echo commands. Exactly what the for/tail loop would produce. But 2000 bytes out of 324 GB tells me nothing about what filled the rest.

Since stdout is redirected directly to the file, writes should stop when the bash process exits. Yet the file grew for 16 minutes. Either the bash process itself stayed alive far longer than the for loop, or something else was writing to that file.

Growing in the Background

With the command now running in the background, Claude Code tried to check on its agents via TaskOutput, but all five calls returned “No task found” in 1 ms. It also checked the bash task, calling TaskOutput with block: true and a 10-second timeout, and got back ~30,000 characters of output containing agent JSONL with MCP tool permission denials. Claude Code concluded the agents were “running into permission issues with web search” and decided it had “enough domain knowledge” to proceed without them.

It moved on to rewriting the document. The background bash task kept running.

The agents had delivered their results to the notification queue 2 minutes earlier. Those notifications sat for 10 minutes while Claude Code generated a 52 KB rewrite of the document, then were all dequeued simultaneously. It scanned the findings and applied a few extra details via targeted edits.

Meanwhile, bday3zjvd.output kept growing.

16 minutes after backgrounding, I noticed the task was still alive. I selected it in the task list, saw infinite scrolling output, and killed it:

⏺ Background command "Check last lines of each agent output" was stopped

No Task Found

Those five “No task found” errors deserve a closer look. They left Claude Code unable to poll for agent status, so it read the bash task’s output instead and mistakenly concluded the agents had failed:

⏺ Task Output(non-blocking) ab82d716c855dd5ba
  ⎿  Error: No task found with ID: ab82d716c855dd5ba

⏺ Task Output(non-blocking) a2ded7593505f4524
  ⎿  Error: No task found with ID: a2ded7593505f4524

⏺ Task Output(non-blocking) a9bffb61f67ddceae
  ⎿  Error: No task found with ID: a9bffb61f67ddceae

⏺ Task Output(non-blocking) a417efc2a4f409639
  ⎿  Error: No task found with ID: a417efc2a4f409639

⏺ Task Output(non-blocking) a4b988afd22aa8db1
  ⎿  Error: No task found with ID: a4b988afd22aa8db1

The agents had finished 30 seconds before these calls. There’s a known bug where Claude Code removes completed tasks from the registry too early, but I think something simpler is going on here. Every call returned in 1 ms, as if the IDs weren’t recognized at all.

Compare that to the bash task bday3zjvd, which TaskOutput found instantly. The IDs even look different: agents get an a prefix with long hex, bash tasks get a b prefix with short alphanumeric. TaskOutput doesn’t seem to recognize agent IDs. Others have reported a similar issue .

Cleanup and Prevention

After killing the task, I needed to reclaim the space. Check how much background tasks are using:

$ du -sh /private/tmp/claude-*/
324G    /private/tmp/claude-501/

Then remove the project subdirectory that’s consuming space:

$ rm -rf /private/tmp/claude-501/<project-path>

Free space went from 21 GB to 344 GB.

On macOS, /private/tmp is not reliably cleaned on reboot. These files can persist indefinitely.

You may set CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1 to disable background tasks entirely. This prevents .output files from growing unchecked, but also means Claude Code can’t run long commands while continuing other work.

Reflections

This bug is quiet. No warnings, no errors, no disk space alerts. I caught it only because I happened to notice the background task indicator still blinking. If I hadn’t, it would have filled the disk.

Other users have reported similar .output file growth: 537 GB , 160 GB , 740 GB . The triggers vary (some involve failing commands dumping error output), but the underlying problem is the same: unbounded .output files with no cleanup. As of March 2026, no built-in fix exists. If your Mac is unexpectedly low on space, check /private/tmp/claude-*.

I checked the first 2000 bytes of the file before deleting it, but that only showed the normal for/tail output. I should have checked the middle or end to see what was filling the other 324 GB.

Claude Code ships daily. That pace is impressive, but 3,617 open bugs is the other side of it, and the quiet ones are the most expensive.

Also available via RSS, Telegram, or X (@rdiachenko)
Questions or ideas? Email me

Explore More Posts