I Found a Bug in Apple's Fsck_hfs

zdw1 pts0 comments

I Found a Bug in Apple’s fsck_hfs — Here’s How I Tracked It Down | by Kivanc G | Apr, 2026 | MediumSitemapOpen in appSign up<br>Sign in

Medium Logo

Get app<br>Write

Search

Sign up<br>Sign in

I Found a Bug in Apple’s fsck_hfs — Here’s How I Tracked It Down

Kivanc G

9 min read·<br>Apr 15, 2026

Listen

Share

TL;DR: fsck_hfs in macOS Sequoia (version hfs-683.x) has a cache exhaustion bug that reports false corruption on large HFS+ volumes. On machines with 8 GB RAM, volumes of 24 TB or larger trigger "Couldn't read node" errors during the extended attributes check. Your data is fine — the bug is in the tool, not the filesystem. Machines with 16 GB+ RAM are unaffected, as are older macOS versions

If you’ve been following my adventures with the HFS+ 24TB volume bug, this is the sequel. In my previous post, I documented a persistent corruption error on my 24TB external HDD. This time, I’m going to show how I traced the error all the way down to its root cause — and it wasn’t what I expected.<br>Spoiler: the filesystem was fine all along. The bug is in fsck_hfs itself.

The Setup<br>I have a 24TB external HDD formatted as Journaled HFS+. Every time I run fsck_hfs on my Mac mini M1, it fails with the same error:<br>** Checking extended attributes file.<br>Couldn't read node #61432<br>** The volume 24TB TOSHIBA could not be verified completely.<br>volume check failed with error 12Error 12 is ENOMEM — "not enough memory." On a machine with 8 GB of RAM? For a filesystem check? Something didn't add up.<br>The error was perfectly reproducible. Same node number, every time. Even on a freshly formatted volume with barely any data. That ruled out progressive data corruption and pointed to something deterministic.

Ruling Out Hardware<br>My first suspicion was hardware — maybe the USB bridge chip in the enclosure was corrupting data, or the drive itself had a defect. But the same error appeared on a completely different 24TB drive with a different enclosure and bridge chip. Two different drives, same error at the same node number. That already pointed away from hardware.<br>To be thorough, I checked the kernel logs with dmesg and monitored I/O with fs_usage during the fsck run:<br>sudo fs_usage -w -f diskio fsck_hfsZero I/O errors. Clean, linear reads throughout the entire check. The data coming off the disk was fine. Whatever was failing, it wasn’t the hardware.

Reading the On-Disk Structures<br>If the hardware was clean, maybe the filesystem metadata itself was corrupt. I decided to dump and parse the raw volume header to see what the Attributes B-tree looked like.<br>The HFS+ volume header lives at byte offset 1024 (sector 2) of the partition:<br>sudo xxd -l 1024 -s 1024 /dev/rdisk7s2Parsing this revealed the Attributes file fork data: 512 MiB logical size, a single contiguous extent starting at allocation block 36588, with 16,384 allocation blocks at 32KB each.<br>Next, I read the B-tree header node — the first 8192 bytes of the Attributes file itself:<br>sudo xxd -l 512 -s 1198915584 /dev/rdisk7s2The B-tree header told me everything:<br>Node size: 8192 bytes<br>Total nodes: 65,536 (filling the entire 512 MiB file)<br>Free nodes: 65,341<br>Used nodes: 195<br>Last leaf node: 155<br>Tree depth: 3<br>So the Attributes B-tree had 65,536 node slots but was only using 195 of them. The active tree lived entirely within the first ~155 nodes. Node #61432 was deep in the unused region.<br>Does node #61432 even fit in the file? At 8192 bytes per node, node #61432 sits at byte offset 503,250,944 — well within the 536,870,912-byte file. It was in bounds.<br>Is node #61432 marked as in-use in the bitmap? The B-tree node-usage bitmap is stored as record 2 of the header node. I calculated that node #61432 corresponds to byte 7679, bit 7 (MSB-first) of the bitmap. Reading that region:<br>sudo xxd -l 512 -s $((1198915584 + 8192 - 512)) /dev/rdisk7s2All zeros in that area. Node #61432 was correctly marked as free.<br>What’s on disk at node #61432?<br>sudo xxd -l 256 -s $((1198915584 + 61432 * 8192)) /dev/rdisk7s2All zeros. Completely empty, as a free node should be.<br>Every on-disk structure was valid and internally consistent. The volume header was correct, the B-tree header was correct, the bitmap correctly marked node 61432 as free, and the node itself was properly zeroed. There was nothing wrong with the filesystem.

Finding the Code<br>Since the data was fine, the bug had to be in fsck_hfs. Apple open-sources HFS+ as part of their Darwin releases, so I cloned the repository:<br>git clone https://github.com/apple-oss-distributions/hfs.gitA quick grep found the error message:<br>grep -rn "Couldn.t read node" --include="*.c"Two hits: SRepair.c and SVerify2.c. The relevant code in SVerify2.c was the function BTCheckUnusedNodes:<br>int BTCheckUnusedNodes(SGlobPtr GPtr, short fileRefNum, UInt16 *btStat)<br>BTreeControlBlock *btcb = GetBTreeControlBlock(fileRefNum);<br>unsigned char *bitmap = ...;<br>unsigned char mask = 0x80;<br>UInt32 nodeNum; for (nodeNum = 0; nodeNum totalNodes; ++nodeNum)<br>if ((*bitmap & mask) == 0) // Node is FREE<br>// Read the...

node error tree fsck_hfs data volume

Related Articles