This is my first issue on bitcoin/bitcoin, so apologies in advance if anything is in the wrong place. I'm happy to provide more data or run tests.
Is there an existing issue for this?
I searched and found none. The change involved is #35465 ("coins: compact chainstate regularly"). It fixes #35298 and was backported to 29.4, 30.3 and 31.1 (#35450, #35452, #35331). I observed this on v32.0rc3. As far as I can tell, v32.0rc4 and current master have no changes to this code.
Current behaviour
A pruned mainnet node ran out of disk space during what appears to be the new periodic background chainstate compaction. The node detected the low disk space and ran its shutdown sequence, but the process never exited, so the node stayed down until it was stopped by hand about 5.7 hours later.
The same node had completed a full compaction about 10 hours earlier using very little extra space. The failing compaction needed more than 5 GiB extra.
Setup
- 25 GiB volume (24.9 GiB usable), XFS. The datadir is on the same volume.
- 5.03 GiB free (79.8% used) immediately before the failing compaction.
- Chainstate: 10.5 GiB in 327
.ldbfiles.
Disk figures are from telegraf, sampled once a minute, so short peaks between samples are not captured.
First compaction on this node: completed normally (2026-10-19)
All 327 chainstate .ldb files were rewritten between 20:45 and 20:48 UTC.
| Time (UTC) | Free | Note |
|---|---|---|
| 20:46 | 4.17 GiB | before |
| 20:47 | 3.95 GiB | lowest sample |
| 20:50 | 4.94 GiB | after (0.77 GiB reclaimed) |
Second compaction on this node: filled the disk (2026-10-20)
| Time (UTC) | Free | Event |
|---|---|---|
| 06:56 | 5.03 GiB (79.8% used) | |
| 06:55-06:57 | 191 new .ldb files (5.07 GiB, file numbers 523645-523835) were written to chainstate/. None of the 327 existing files were deleted. Chainstate grew from 10.5 GiB to 15.6 GiB. |
|
| 06:57 | 4.30 GiB | |
| 06:58 | 0.67 GiB | |
| 06:59 | 0 (100% used) | |
| 07:01:43 | The next block could not be written. Disk space is too low!, AcceptBlock FAILED, and the node began shutting down. |
|
| 07:01:46 | Failed to force flush state (Disk space is too low!), then Shutdown done. |
|
| 07:01:46-12:42 | The process did not exit. systemd logged nothing for the service, and with the process still alive, Restart=always never triggered. |
|
| 12:42:01 | Manual systemctl stop. SIGTERM had no effect. |
|
| 12:44:01 | Stop timeout (2 min) expired. systemd killed the process with SIGKILL (Failed with result 'timeout'). |
Nothing was logged about either compaction at the default log level, because the start and finish messages are LogDebug(BCLog::COINDB). debug.log has no entries between 06:48:41 and the first error at 07:01:43. The timing above comes from file modification times and the disk metrics.
After restart. When the node was restarted, LevelDB removed the partial outputs and the chainstate returned to 10.5 GiB. The node then synced normally.
A second node. This node has the same version and configuration and the same 25 GiB volume. It did a full compaction on 2026-10-17 (all 329 files rewritten, 11:29-11:32 UTC) and completed it. However, about 2 GiB of extra disk usage remained for more than two hours after the compaction's file writes had stopped:
| Time (UTC) | Free | Note |
|---|---|---|
| 11:29 | 6.15 GiB | before |
| 11:30 | 4.80 GiB | |
| 11:31 | 5.30 GiB | |
| 11:32 | 5.98 GiB | |
| 11:33 to 13:47 | 4.15 GiB | steady, about 2 GiB below the starting level |
| 13:48 | 6.17 GiB | released all at once |
debug.log on that node has nothing around 11:33 or 13:48 apart from normal block processing. Nothing on either node calls gettxoutsetinfo, scantxoutset or dumptxoutset.
Comparison with the PR measurements. In #35465, a simulation of 22 compactions reported at most 1.06 GiB of temporary extra disk space. The first compaction on the failing node matches that. The second one wrote more than 5 GiB of new table files without releasing any input files, and its true peak was higher because it did not finish.
Possible explanation (from reading the code, not confirmed)
I have not been able to confirm this, because -debug=leveldb was not enabled. From reading the LevelDB code in the tree:
- Obsolete
.ldbfiles are only removed inDBImpl::DeleteObsoleteFiles(), which runs in three places: after a memtable compaction, after each background or manual compaction step, and atDB::Open. - Any file still referenced by a live
Versionat that moment is kept. When the last reference is dropped later,Version::Unref()frees theVersionbut does not trigger deletion, so the file stays on disk until the nextDeleteObsoleteFiles()call. - The chainstate is only written during Core's periodic flushes (every 50-70 minutes), so the next call can be an hour or more away.
That could explain the second node: the final step of the full compaction has no later step to clean up after it, and the ~2 GiB held matches the size of that step's output (58 files, 1.99 GB, written at 11:32). The space was released at 13:48, which is about two flush intervals after the compaction (it was triggered by a flush at about 11:29). I don't know why it wasn't released at the first flush after the compaction, or what was holding a reference.
If something held an old Version for a long time on the failing node, it could also explain why none of the 327 input files were deleted while 191 output files were written, even though every compaction step calls DeleteObsoleteFiles(). The other possibility is that one or more steps were very large. My guess is that it matters that this compaction ran only about 10 hours after a previous full compaction, when all files are in the bottom level. The data I have can't tell these apart.
The post-shutdown hang. This may be a separate issue. When systemd finally killed the process, the remaining threads were the main thread (named b-shutoff) and two b-capnp-loop threads. This is a multiprocess build, and a mining client was connected over IPC at the time. The hang turned what would have been a short outage (the restart recovered immediately) into a 5.7-hour one. I'm happy to open it as its own issue if that's preferred.
Expected behaviour
Periodic maintenance compaction should not be able to take a running node down. For example:
- Check available disk space (for example, against the chainstate's on-disk size) before starting a full compaction, and skip or postpone it if there isn't enough headroom.
- Make sure obsolete table files are released promptly once a compaction finishes, rather than waiting for a later write.
- Log the start and finish of the compaction at the default log level, so operators can relate disk usage spikes to it.
- Optionally, provide a way for operators to disable or defer the compaction.
Separately, after a fatal error and Shutdown done, the process should exit so that a service manager can restart it.
Steps to reproduce
Not deterministic, because the trigger is a random 1/320 chance after each full flush. Conditions here:
- Pruned node (
prune=550). - 25 GiB volume with about 5 GiB free.
- A full compaction about 10 hours before the failing one.
I can try to reproduce on a copy of the chainstate (for example with -forcecompactdb and -debug=leveldb), or run with -debug=leveldb -debug=coindb until the next compaction. If there's a lower-overhead way to capture the relevant LevelDB events on a production node, I'd be glad to use it.
Relevant log output
debug.log:
2026-10-20T07:01:43.207490Z [error] A fatal internal error occurred, see debug.log for details: Disk space is too low!
2026-10-20T07:01:43.210613Z [error] FindNextBlockPos failed for FlatFilePos(nFile=-1, nPos=0) while writing block
2026-10-20T07:01:43.212811Z Shutdown in progress...
2026-10-20T07:01:43.212507Z [error] ProcessNewBlock: AcceptBlock FAILED (AcceptBlock: Failed to find position to write new block to disk)
2026-10-20T07:01:43.306973Z [error] SerializeFileDB: Failed to open file /data/.bitcoin/peers.fb8d
2026-10-20T07:01:43.307578Z [error] SerializeFileDB: Failed to open file /data/.bitcoin/anchors.bb45
2026-10-20T07:01:46.092854Z [error] A fatal internal error occurred, see debug.log for details: Disk space is too low!
2026-10-20T07:01:46.092888Z [warning] Failed to force flush state (Disk space is too low!)
2026-10-20T07:01:46.106919Z [error] A fatal internal error occurred, see debug.log for details: Disk space is too low!
2026-10-20T07:01:46.107061Z [warning] Failed to force flush state (Disk space is too low!)
2026-10-20T07:01:46.899647Z Shutdown done
systemd (no entries for the service between 07:01 and 12:42):
12:42:01 systemd[1]: Stopping bitcoin-node.service...
12:44:01 systemd[1]: bitcoin-node.service: State 'stop-sigterm' timed out. Killing.
12:44:01 systemd[1]: bitcoin-node.service: Killing process 3463 (b-shutoff) with signal SIGKILL.
12:44:01 systemd[1]: bitcoin-node.service: Killing process 3466 (b-capnp-loop) with signal SIGKILL.
12:44:01 systemd[1]: bitcoin-node.service: Killing process 3486 (bitcoin-node) with signal SIGKILL.
12:44:01 systemd[1]: bitcoin-node.service: Killing process 3303146 (b-capnp-loop) with signal SIGKILL.
12:44:01 systemd[1]: bitcoin-node.service: Main process exited, code=killed, status=9/KILL
12:44:01 systemd[1]: bitcoin-node.service: Failed with result 'timeout'.
Chainstate .ldb files by modification time, while the process was hung:
2026-10-19T20:45 72 files 2.49 GB
2026-10-19T20:46 106 files 3.66 GB
2026-10-19T20:47 107 files 3.70 GB
2026-10-19T20:48 42 files 1.44 GB
2026-10-20T06:55 55 files 0.78 GB
2026-10-20T06:56 113 files 3.91 GB
2026-10-20T06:57 23 files 0.76 GB
How did you obtain Bitcoin Core
Compiled from source
What version of Bitcoin Core are you using?
v32.0rc3 (2633a1ded5) plus two local commits that don't touch src/leveldb, dbwrapper, txdb, coins or validation. Multiprocess build, run as bitcoin-node -ipcbind=unix under systemd (Type=simple, Restart=always).
Operating system and version
Amazon Linux 2023
Machine specifications
AWS EC2 instance with a 25 GiB EBS volume (XFS).
Relevant config:
prune=550
dbcache=2500
maxmempool=300
persistmempool=1