Skip to content

cargo-target build caches have no retention policy — 96 dirs reached 1,155 GiB and took the shared volume to 0 bytes free (cause of #3797) #3798

Description

@tomerweller

cargo-target/ build caches on the shared volume have no retention policy — 96 of them reached 1,155 GiB and took the volume to literally zero free bytes, killing the mainnet validator for 8 d 10 h (#3797) and every automated loop on the host

Filed at the request of #3749's resolution comment: "A cargo-target retention policy is the real fix. Reclaiming 1.15 TB by hand resolves the symptom; nothing currently prevents 96 more build caches from accumulating to the same point. … Worth its own issue if one doesn't already exist." Confirmed none does — searched cargo-target retention, retention policy build cache in:title, and dedupe dispatch worktree across open and closed issues.

The number

At 2026-08-08T22:45Z, immediately before the manual cleanup:

/dev/nvme1n1   1.7T used   0 bytes free   100%

96 co-tenant */cargo-target/ dirs          ~1,155 GiB
mainnet/ (live validator dataset)           172.30 GiB
74535976/ (monitor session)                   4.51 GiB

Every one of the 305 co-tenant trees was idle ≥ 9.3 days; 239 were idle > 30 d, the largest single tree idle 44 d. No process on the host held a cwd inside /home/tomer/data — every /proc/*/cwd was scanned. The entire 1.15 TB was regenerable compiler output that nothing was reading.

After the cleanup, 2 cargo-target dirs remain, and the retention gap is already visible in them:

  85.58 GiB  idle 37.8 d  b0db5fda    <- skipped: live open fd elsewhere in the tree
   3.79 GiB  idle 87.4 d  74535976    <- the monitor's own; holds the deployed binary

b0db5fda alone is 85.58 GiB of 37-day-idle build cache that survived only because an unrelated zsh had a log file open elsewhere under the same session dir. A policy keyed on the session being live will keep re-making that mistake; the unit of retention has to be the cargo-target directory itself.

Why this is worth a policy and not a cron rm

The failure was non-linear, and that is the part the "~11-day runway" framing in #3749's title got wrong:

  1. Growth is bursty, not steady — 6 trees arrived in a 9 h window on 07-30, none in the 17.9 h before the volume filled.
  2. At zero free bytes the recovery mechanisms die too. project-loop-watchdog.sh failed on every firing from 2026-07-31T13:30Z with could not create work tree dir … No space left on device; it could not clone a scratch checkout to run the headless tick that would have noticed. The backstop was disabled by exactly the condition it existed to survive.
  3. So the observable signal is not a gentle slope into a warning — it is 8.8 days of total silence. See URGENT: mainnet validator OFFLINE 8d10h — ENOSPC kill at 2026-07-31T12:34:56Z, zero alarm signal (recurrence of closed #3478) #3797 §6 for the monitor-side equivalent (three independently-correct gates that together emitted nothing).

A threshold alert on free space would not have helped either: #3749 had one, it fired for weeks, and the reclaim it asked for needed an authorization that no automated actor held.

Suggested policy

Sized to what the census above actually shows:

  1. Age-based reclaim of */cargo-target/ specifically, not of session dirs. Delete any cargo-target whose mtime is older than N days (N=7 would have been safe for all 96 — minimum idle was 9.3 d). Leave every sibling path alone: source trees, worktrees, logs, and diagnostic artifacts were correctly excluded by the manual cleanup and should be excluded structurally.
  2. Skip on open file handles, but scope the skip to the cargo-target dir, not the parent session. The manual pass skipped the whole of b0db5fda because of an fd on maxtps-opt/live-bandiag.log; 85.58 GiB of unrelated build cache rode along.
  3. Exempt an explicit allowlist — at minimum mainnet/ and the live monitor session's cargo-target, which holds the deployed validator binary (74535976/cargo-target/release/henyey, currently 0ac84d42). Deleting that one would turn a disk-pressure event into an unrecoverable one.
  4. A shared CARGO_TARGET_DIR is the alternative worth costing out. Per-session target dirs are why the same dependency graph is compiled 96 times; one shared cache with cargo's own eviction would remove the class rather than trimming it. The tradeoff is lock contention between concurrent agent builds, which is why this is listed as an alternative and not the recommendation.
  5. Report what was reclaimed. The manual pass produced a clean before/after; an automated one should too, or the next investigator sees a volume that shrank for unexplained reasons — the same ambiguity that made me mis-read buckets/ shrinkage as a sustained reclamation rate on Shared data volume /home/tomer/data at 95% — ~11-day exhaustion runway #3749.

Related

Reproduce

# per-cargo-target census with idle age — the unit a policy should act on
python3 - <<'EOF'
import os, time
base='/home/tomer/data'; now=time.time()
for d in sorted(os.listdir(base)):
    p=os.path.join(base,d,'cargo-target')
    if os.path.isdir(p):
        s=sum(os.lstat(os.path.join(r,f)).st_size
              for r,_,fs in os.walk(p, onerror=lambda e:None) for f in fs)
        print("%8.2f GiB  idle %5.1f d  %s"%(s/2**30,(now-os.stat(p).st_mtime)/86400,d))
EOF

# nothing is holding any of it
for p in /proc/[0-9]*; do readlink $p/cwd; done | grep -c '^/home/tomer/data/'

Node state

Catching Up — relaunched 2026-08-08T23:07:42Z on 0ac84d42 (henyey-v27.0.0-alpha.1) from persisted lcl 63,733,600 after the 8 d 10 h outage; restore-from-disk in progress, being watched for the #3702 near-tip stall. Volume 1,155.9 GiB free / 31 %. Deploys held on #3702.

Not filed urgent — the acute symptom is #3797 and the volume is no longer under pressure; this is the durable fix that stops it recurring.

/monitor-tick 2871

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions