nix-nightly-build.service on lucie ran away on the night of 2026-08-28 and starved the whole host of I/O for 4.5 hours, taking down Nextcloud, journald and eventually the entire box. It required a hardware reset.
What happened
Aug 28 03:02:34 Starting Nightly NixOS devbox configuration build...
Aug 28 07:30:35 nix-nightly-build.service: start operation timed out. Terminating.
Aug 28 07:31:01 Main process exited, code=killed, status=15/TERM
Aug 28 07:32:31 State 'final-sigterm' timed out. Killing.
Aug 28 07:32:32 Failed with result 'timeout'.
Aug 28 07:32:32 Consumed 4h 2min 35.881s CPU time over 4h 29min 57.792s wall clock time,
8.1G memory peak, 748M memory swap peak,
55.4G read from disk, 47.7G written to disk,
10.7G incoming IP traffic, 40.8M outgoing IP traffic
For comparison, every previous run in the journal finished in 1-5 minutes (worst case ~40 min on Aug 24 and Aug 26).
Cause
nix flake update picked up a nixpkgs bump that invalidated the CUDA 12.9 closure. The build log shows it downloading and building the CUDA redistributables:
Aug 28 05:05:12 building '/nix/store/dvxz1p7pnpqm3ihvs47vxb9wp1abl0fz-cuda12.9-cuda_nvdisasm-12.9.88.drv'...
Aug 28 05:05:12 building '/nix/store/j0nmkrar6mghrlylrkgbp9rzp37xqbml-cuda12.9-cuda_nvml_dev-12.9.79.drv'...
Aug 28 05:05:13 building '/nix/store/524vzfhim1nqzajpq7awa0bl597m6c3y-cuda12.9-cuda_nvprune-12.9.82.drv'...
Aug 28 05:05:30 building '/nix/store/j2c2336p9k3iy7qddhcr5pydpp7gglhb-cuda12.9-cuda_nvcc-12.9.86.drv'...
Aug 28 05:06:32 building '/nix/store/xnv50bgq97ahnzw8j2capsx7d6m9yfg7-cuda12.9-cuda_nvrtc-12.9.86.drv'...
Aug 28 05:07:04 building '/nix/store/44wysgg5ir8pkgjl6c37ag27589vyhfm-cuda12.9-cuda_sanitizer_api-12.9.79.drv'...
After 05:07:04 the service logged nothing for 2h23m — that is when the host was thrashing.
47.7 GB of writes onto a root filesystem that is at 96% (/dev/nvme0n1p1 3.6T 3.3T 150G 96% /) was enough to stall the ext4 journal outright.
Why the existing guards did not help
hosts/lucie/nightly-build.nix sets Nice=19 and IOSchedulingClass=idle, but neither limits the thing that actually broke:
IOSchedulingClass = "idle" is a no-op on this host. /sys/block/nvme0n1/queue/scheduler reads [none] mq-deadline kyber. ionice scheduling classes are only honoured by BFQ (and the old CFQ). Under none the build got zero I/O throttling.
Nice = 19 only affects CPU. It does nothing about dirty page pressure. With vm.dirty_ratio = 20 on 62 GB of RAM the build could pin ~12 GB of dirty pages, repeatedly.
- No memory limit. 8.1 GB peak + page cache pressure triggered the global OOM killer.
TimeoutStartSec = "4h" is too generous. It did fire, but only at 07:30 — the host had already been unusable since ~03:20. A build that normally takes 5 minutes does not need a 4 hour budget.
Collateral damage
| Time |
Event |
| 03:02:34 |
nightly build starts |
| 03:18:30 |
nextcloud-cron.service: condition operation timed out. Terminating. |
| 03:22:23 |
phpfpm-nextcloud.service: Watchdog timeout (limit 15s)! — all 20 workers SIGABRT'd. Nextcloud down from here on |
| 03:22:49 |
coredump storm: systemd-coredump.socket: Too many incoming connections (9), over core_pipe_limit, skipping core dump |
| 05:04:44 |
global OOM killer fires, kills chromium |
| 07:31:09 |
INFO: task jbd2/nvme0n1p1-:302 blocked for more than 245 seconds in jbd2_journal_wait_updates — ext4 journal stopped committing. journald, nix, transmission, Plex, chromium all pile up in ext4_dirty_inode |
| 07:31:09 |
systemd-journald SIGABRT'd by its own watchdog; journal at 3.9G, max 4G, 46.6M free, replayed a 4 hour backlog on restart |
| 07:46:15 |
hardware reset |
No hardware fault involved: no NVMe errors, no controller resets, no EXT4-fs error in the kernel log. This was pure write-pressure starvation.
Recurrence
The build was killed at its timeout, so the CUDA closure was never completed or committed. The timer fires again tonight at 03:00 and will redo the same work.
Proposed fix
In hosts/lucie/nightly-build.nix:
serviceConfig = {
# ...
MemoryHigh = "4G"; # throttle rather than OOM the host
MemoryMax = "8G";
TimeoutStartSec = "1h"; # 4h let it wedge the box overnight
};
IOSchedulingClass = "idle" should either be dropped or paired with switching nvme0n1 to BFQ, otherwise it is misleading dead config.
The knob that actually bites under the none scheduler is capping dirty pages globally, e.g. vm.dirty_bytes = 2147483648 (2 GB) in place of the 12 GB that vm.dirty_ratio = 20 currently permits. That alone would have kept jbd2 committing while the build ran.
Worth considering separately: root is at 96% and /mnt/storage at 99%, which makes ext4 allocation under heavy write markedly worse.
nix-nightly-build.serviceon lucie ran away on the night of 2026-08-28 and starved the whole host of I/O for 4.5 hours, taking down Nextcloud, journald and eventually the entire box. It required a hardware reset.What happened
For comparison, every previous run in the journal finished in 1-5 minutes (worst case ~40 min on Aug 24 and Aug 26).
Cause
nix flake updatepicked up a nixpkgs bump that invalidated the CUDA 12.9 closure. The build log shows it downloading and building the CUDA redistributables:After 05:07:04 the service logged nothing for 2h23m — that is when the host was thrashing.
47.7 GB of writes onto a root filesystem that is at 96% (
/dev/nvme0n1p1 3.6T 3.3T 150G 96% /) was enough to stall the ext4 journal outright.Why the existing guards did not help
hosts/lucie/nightly-build.nixsetsNice=19andIOSchedulingClass=idle, but neither limits the thing that actually broke:IOSchedulingClass = "idle"is a no-op on this host./sys/block/nvme0n1/queue/schedulerreads[none] mq-deadline kyber. ionice scheduling classes are only honoured by BFQ (and the old CFQ). Undernonethe build got zero I/O throttling.Nice = 19only affects CPU. It does nothing about dirty page pressure. Withvm.dirty_ratio = 20on 62 GB of RAM the build could pin ~12 GB of dirty pages, repeatedly.TimeoutStartSec = "4h"is too generous. It did fire, but only at 07:30 — the host had already been unusable since ~03:20. A build that normally takes 5 minutes does not need a 4 hour budget.Collateral damage
nextcloud-cron.service: condition operation timed out. Terminating.phpfpm-nextcloud.service: Watchdog timeout (limit 15s)!— all 20 workers SIGABRT'd. Nextcloud down from here onsystemd-coredump.socket: Too many incoming connections (9),over core_pipe_limit, skipping core dumpINFO: task jbd2/nvme0n1p1-:302 blocked for more than 245 secondsinjbd2_journal_wait_updates— ext4 journal stopped committing. journald, nix, transmission, Plex, chromium all pile up inext4_dirty_inodesystemd-journaldSIGABRT'd by its own watchdog; journal at3.9G, max 4G, 46.6M free, replayed a 4 hour backlog on restartNo hardware fault involved: no NVMe errors, no controller resets, no
EXT4-fs errorin the kernel log. This was pure write-pressure starvation.Recurrence
The build was killed at its timeout, so the CUDA closure was never completed or committed. The timer fires again tonight at 03:00 and will redo the same work.
Proposed fix
In
hosts/lucie/nightly-build.nix:IOSchedulingClass = "idle"should either be dropped or paired with switchingnvme0n1to BFQ, otherwise it is misleading dead config.The knob that actually bites under the
nonescheduler is capping dirty pages globally, e.g.vm.dirty_bytes = 2147483648(2 GB) in place of the 12 GB thatvm.dirty_ratio = 20currently permits. That alone would have kept jbd2 committing while the build ran.Worth considering separately: root is at 96% and
/mnt/storageat 99%, which makes ext4 allocation under heavy write markedly worse.