[BUG] Hook output and tool-result capture files in /tmp/claude-{uid}/<cwd>/tasks/ accumulate ~19MB null padding per file (missing ftruncate)
Environment
- OS: Linux 6.17 (Ubuntu 24.04)
- Claude Code: VS Code extension (anthropic.claude-code 2.1.131-linux-x64)
- Auth: claude.ai OAuth (subscription)
maxOutputTokens: was 128000 (now lowered to 32000 as a workaround)
Summary
Files written to /tmp/claude-{uid}/<cwd-slug>/<session-id>/tasks/hook_<pid>.output (the path used to capture hook stdout that exceeds the documented 10K char inline cap, and the same path used for large tool-subagent results per #26911) are observed at ~19,562,240 bytes each, of which only ~9 KB is the actual captured output. The remainder is a contiguous tail of NULL bytes.
Math: 19,562,240 / 128,000 ≈ 153 bytes per maxOutputToken — strongly suggests the runtime pre-allocates a buffer sized to maxOutputTokens × bytes-per-token-upper-bound, then writes the actual (much smaller) captured output without subsequently calling ftruncate(fd, real_size) or opening with O_TRUNC. This is the same bug class documented in #51435 for the skill-upload writer.
Reproduction
- Configure a
SessionStart:compacthook that emits >10K chars of stdout (e.g., the user'scompact-context-reinject.shwhichcats aCONTEXT_STATE.md-style file). - Use Claude Code in the project for several sessions.
- ```bash
du -sh /tmp/claude-$(id -u)/-home-*/tasks/
```
Accumulates ~19 MB per stdout-capturing hook fire (~80–100 MB per project per session in heavy use).
- ```bash
od -c /tmp/claude-$(id -u)/<project>/<session>/tasks/hook_<pid>.output | head -5
``\\0 \\0 \\0 ...`).
Confirms NULL prefix (
- ```bash
stat <file>
``Blocks * 512 ≈ apparent size` — file is real on disk, NOT sparse.
Local file shape (verified on user's machine):
0000000 \0 \0 \0 \0 \0 \0 \0 \0 ... (continues for ~19.55 MB)
*
0112520374 m ( p e r - s t e p ... (real stdout starts at offset ~19.55 MB)
0112526337
File size: 19,570,940 bytes. Real content: last ~8.7 KB. Prefix: ~19.55 MB of NULLs.
Impact
- Disk leak: ~19 MB per stdout-capturing hook fire; 80–100+ MB per project per session.
- Compounds existing #26911 (no cleanup of
tasks/.outputfiles at all). - Possibly contributes to GUI freeze symptoms of #23053 / #51560 when the runtime later reads these files back for context injection (extra MB of NULLs to scan/skip).
Suggested fix
After the captured output is written and before the file is closed, call ftruncate(fd, actualBytesWritten). Alternatively open with O_TRUNC on each new capture. Same fix shape proposed for #51435.
Relation to other issues
- Same path as #26911 (no cleanup) — fixing this would not remove the need for cleanup, but it would reduce per-file size by ~99.95%, making the existing accumulation far less harmful.
- Same bug class as #51435 (missing
ftruncatein another writer). - Possibly contributes to symptoms of #23053 / #51560 (large-payload streaming freeze) by inflating bytes the runtime later re-reads from these files into the chat stream.
Workaround we deployed locally
SessionStart/Stop hook that runs find /tmp/claude-$(id -u) -path '*/tasks/hook_*.output' -size +1M -delete. Real hook stdout is always tiny so the 1 MB threshold is safe.
Additional observation
The user's project-level maxOutputTokens: 128000 may be unusually high (default is lower). Lowering it to 32000 reduces the per-file disk waste by 4×. Worth documenting that this setting affects disk usage in /tmp until the underlying truncation bug is fixed.
---
Investigation report (private to user, but happy to share excerpts): the bloated null-padded files were initially suspected to cause the "Transmuting…" GUI freeze, but on closer reading the freeze itself is more likely the streaming-time main-thread stall already documented in #23053 / #51560. The disk leak documented here is a separate, real bug.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗