Temp-filesystem preflight false-positives ENOSPC on filesystems with >17.6 TB free (statfs 32-bit truncation)
Bug report: temp-filesystem preflight false-positives "ENOSPC" on large (>17.6 TB) filesystems
Product: Claude Code CLI
Affected versions: 2.1.153 → 2.1.158 (latest at time of writing). Not present in ≤ 2.1.152.
Severity: Tool execution aborts ("Command output was lost") on filesystems that are nowhere near full.
Summary
Since 2.1.153, Claude Code runs a free-space preflight before capturing a
child process's stdout/stderr to its temp filesystem. On a filesystem with
more than ~17.6 TB of free space, the check computes a negative free-MB
value (due to a 32-bit truncation of f_bavail in the JS runtime's fs.statfs
binding) and aborts with:
Command output was lost: the temp filesystem at <dir> is full (-4469490MB free).
The child process's stdout/stderr writes failed with ENOSPC.
Free up space or set CLAUDE_CODE_TMPDIR to a directory on a filesystem with room.
The filesystem is not full — the write would have succeeded. Versions ≤
2.1.152 (which had no preflight) ran on the exact same machine for weeks with
no issue.
Root cause
The preflight (decompiled from 2.1.158) is:
const q = await statfs(dir);
const K = Math.floor(q.bavail * q.bsize / 1048576); // free MB
if (K < 10) return `…is full (${K}MB free)… ENOSPC…`;
if (q.files > 0 && q.ffree < 1000) return `…out of inodes…`;
q.bavail comes from the runtime's fs.statfs, which truncates the kernel's
64-bit f_bavail to a signed 32-bit int. Measured on the affected host
(a containerd overlay rootfs, 112 TB / 45.8 TB free):
| field | kernel (os.statvfs, correct) | runtime (fs.statfs, what CC uses) |
|---|---|---|
| f_bavail | 11,740,712,350 | −1,144,189,538 |
| bavail × bsize | 48,089,957,785,600 (≈ 45.8 TB) | −4,686,600,347,648 |
| → free MB (K) | 45,862,157 | −4,469,491 |
The truncation is exact:
11,740,712,350 mod 2^32 = 3,150,777,758
3,150,777,758 > 2^31 → as int32 = −1,144,189,538 ✓
So any filesystem with > 2^32 free 4 KB-blocks (≈ 17.6 TB free) tripsK < 10 and aborts. Large overlay/NFS/scratch filesystems are common on
build boxes, GPU nodes, and CI runners.
Reproduction
On a host with a >17.6 TB-free filesystem (or any fs whose fs.statfs().bavail
wraps negative — verify with the table below):
# kernel says plenty free:
python3 -c "import os;s=os.statvfs('/tmp');print(s.f_bavail*s.f_bsize//1048576,'MB')"
# runtime truncates to negative:
node -e "const s=require('fs').statfsSync('/tmp');console.log(Math.floor(s.bavail*s.bsize/1048576),'MB')"
# (bun reproduces it identically)
Then run any Bash tool that produces stdout — Claude Code aborts with the
false ENOSPC.
Suggested fixes (either is sufficient)
- Guard the preflight against bogus/negative values — treat a negative
(or otherwise nonsensical) free figure as "unknown, proceed" rather than
"full". Minimal:
``js…is full…
const K = Math.floor(q.bavail * q.bsize / 1048576);
if (K >= 0 && K < 10) return ; // skip the guard when K < 0`
write()` already surfaces a real ENOSPC if the disk is truly
The actual
full, so a negative preflight reading should never block.
- Fix the underlying
fs.statfstruncation in the bundled runtime so
f_bavail/f_blocks/f_bfree are read as 64-bit (this is a
Node/Bun-level binding issue; report there too).
Workaround (current)
Set CLAUDE_CODE_TMPDIR to a directory on a filesystem with < ~17.6 TB free
(any tmpfs such as /dev/shm qualifies), so the block count stays within
32 bits and the preflight reads a sane value.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗