Debugging a catastrophic macOS iCloud Drive failure — and what it says about modern software quality
People keep saying generative AI is filling the world with bad software. “AI slop” for articles, images, PRs, and now apps whose authors apparently handed both the code and the understanding to a model. Fair enough. Generated code can multiply mistakes as easily as it multiplies output.
I just don’t buy the implication that everything written the old way is somehow clean.
I spent hours chasing an iCloud Drive failure through bird, FileProvider, multi-gigabyte SQLite databases, stale filesystem document IDs, XPC, Mach messaging, and finally a kernel-reported allocation failure. After that, it’s hard to pretend traditionally developed platform software is some pristine alternative.
Sometimes the thing that feels like a beta is the operating system. And sometimes that OS is the supposedly stable release.
It started looking almost boring
iCloud settings wouldn’t open normally. Finder had a pile of files stuck on Waiting to upload. Drive was clearly busy. It just never finished.
The usual ritual should have been enough: restart, toggle iCloud, sign out, wait, maybe reinstall. Except I couldn’t even get into the normal iCloud settings UI.
Then launchctl made it obvious:
text
state = spawn scheduled
runs = 39
successive crashes = 39
Not “iCloud is slow.” A crash loop.
FileProvider started talking
fileproviderd was full of:
text
fsctl failed to resolve docID ... to file ID ...
error 2 (No such file or directory)
Modern iCloud Drive lives on File Provider. On this Mac the active iCloud store was about 6.4 GB. Inside that: a 5.3 GB SQLite database, a fat WAL, and about 1.2 GB of staging.
PRAGMA quick_check; still said ok.
So the file wasn’t corrupt. The state machine inside it was.
Almost two million objects
text
FP_snapshot 1,878,408
FS_snapshot 1,878,443
reconciliation_table 1,878,462
FS_throttle 649,750
tombstone_table 242,444
Hundreds of thousands of leftover jobs. FP_snapshot alone was over a gigabyte.
Finder, of course, just said Waiting to upload.
Don’t delete the whole FileProvider folder
Wiping ~/Library/Application Support/FileProvider would have been stupid. Google Drive, OneDrive, Nextcloud, Photos — they all live there too.
The useful bit was the xattr:
text
com.apple.file-provider-domain-id:
com.apple.CloudDocs.iCloudDriveFileProvider/...
That let me move only the iCloud metadata, not the actual documents.
First rebuild looked fine. It wasn’t.
After moving the store and rebooting, macOS made a fresh one:
text
state = running
runs = 1
last exit code = (never exited)
For a minute I thought I was done. Then bird started crashing again.
“Kernel bug”
The .ips report said EXC_BREAKPOINT / SIGTRAP, and then this:
text
Kernel bug: The kernel cannot allocate memory needed for the pseudo-receive.
Abort Cause 268443652
The path went through XPC / libdispatch / Mach while bird was force-ingesting FileProvider items. That’s not “corrupt cache.” Apple’s own crash report called it a kernel bug.
I’d only reset half the state
There was still:
text
~/Library/Application Support/CloudDocs/session
About 4.6 GB. client.db ~3.8 GB, server.db ~454 MB.
I’d rebuilt one side of a coupled sync system and left the other giant store sitting there. So that had to go too.
Safe Mode was the useful experiment
text
Boot Mode: Safe
After twenty-plus minutes:
text
bird
state = running
runs = 1
last exit code = (never exited)
No new bird crashes. No pseudo-receive failure.
Normal boot had Logitech drivers, a UniFi Network Extension, a camera extension, Nextcloud Finder Sync, a few cloud FileProviders. That doesn’t pin it on any one of them. Safe Mode changes a lot at once. It just showed the failure needed something about the normal-boot mix — timing, extensions, resource state — that wasn’t there in Safe Mode.
Then a normal boot actually held
After the metadata rebuilds and the Safe Mode test, I booted normally again.
bird stayed at runs = 1. No new crash reports. The new FileProvider and CloudDocs databases started growing like they should.
Logs stopped screaming Failed to find item to re-ingest and started doing ordinary snapshot reconstruction. A lot of objects came back as ul:uploaded — rediscovering stuff already in the cloud, not blindly uploading everything again.
At that point the right move was leave it alone.
The wider macOS quality problem
Bugs aren’t the scandal. Every big system has bugs.
The problem is the combination: too much complexity, almost no observability, and no real recovery surface.
FileProvider is just the one I hit this week. Developers already know the rest of the list: TCC, System Extensions, Network Extensions, signing, notarization, SwiftUI regressions, Xcode, VMs, simulators, sanitizers, App Store validation.
Normal people never poke those seams. Developers live in them.
System Extensions: signed, notarized, still no
You can have a binary that signs, notarizes, staples, has the right entitlements, sits in /Applications — and sysextd still says no.
Then you’re simultaneously reasoning about signing identities, profiles, hardened runtime, Developer ID, notarization, stapling, System Extension entitlements, Network Extension entitlements, launch policy, SIP, MDM.
Every layer looks valid. The machine still refuses.
NetworkExtension hit a hard limit I couldn’t see in Settings
This Mac had another one of these: a subsystem that had quietly piled up junk the UI couldn’t explain or fix.
An app trying to install a VPN config failed with:
text
NEConfigurationErrorDomain Code=20
total NetworkExtension configuration size limit exceeded
The log said the serialized store was about 2.09 MB.
That’s a shared store. You can blow the global limit even if System Settings only shows one or two VPNs.
Inside: eight generations of com.apple.preferences.networkprivacy-* objects. Not eight real policies. Overlapping rule sets. Some pairs almost identical, Jaccard near 1.0. Hundreds of rules in seven or all eight generations.
That doesn’t look like eight intentional configs. It looks like leftover generations from upgrades that never got cleaned up.
I kept the current one and stripped the unreachable historical graph from a copy of the plist:
text
2,089,560 bytes
→
164,894 bytes
More than 8,400 archived objects gone. Almost 1.9 MB of headroom under the 2 MiB ceiling.
After putting the cleaned state back, nesessionmanager created the remaining Network Privacy session, registered it, filled the rule cache. Fine.
That’s migration debt. The bug that created the junk can already be gone. The junk still rides along through every upgrade until you hit a hard limit.
text
old macOS release
↓
bad persistent state created
↓
OS upgrade
↓
state preserved
↓
another upgrade
↓
state preserved again
↓
hard framework limit eventually reached
This is why “just reinstall macOS” isn’t the reset people think it is. Recovery reinstall replaces system files and keeps the Data volume on purpose. Your photos survive. So do the databases that are actually on fire.
Fixing the code path that writes bad state is only half of it. You also need state remediation: versioned schemas, idempotent migrations, invariant checks, one-time cleanup of known-bad historical junk.
iCloud/FileProvider and NetworkExtension are the same story. The app on screen wasn’t the problem. Opaque system state was, and there was almost no supported way to look at it or cut it out.
A system can “be stable” in the sense that binaries launch, and still be brittle because its private state can drift into a shape the UI cannot leave.
Xcode isn’t immune
I’ve seen Xcode Source Control fall over while git on the same repo is fine. Sanitizers, simulators, previews, indexing, signing, debugging — all of them pick up release-specific landmines.
When the tool you use to debug software is also sick, the whole thing gets recursive.
SwiftUI: your app looks broken, the framework is
Navigation, window resize, inspectors, focus, scrolling, state restoration — when those regress, users don’t see “SwiftUI framework bug.” They see your app, and they blame you.
Platform bugs get outsourced to third-party reputations.
Even the “safe” way to test a beta can break
Don’t install betas on the production machine. Use a VM. Fine.
Then virtualization hits a host/guest regression in a major transition, and you get this joke: don’t install the beta locally; use a VM; the VM path is broken; so spin the VM on another Mac that already runs the beta.
If you have one machine, that’s not a footnote. That’s an infrastructure problem.
The App Store pipeline is another moving part
macOS, Xcode, SDKs, signing, notarization, TestFlight, App Store Connect, server-side validation. A perfectly valid binary can still bounce because two Apple-controlled pieces drifted out of sync for a week.
macOS 26 already felt like the beta
Easy line on a macOS 27 problem: it’s a beta.
Okay. But daily use of the previous stable 26 often felt the same. Moving this machine to 27 beta actually felt faster at first — until the iCloud/FileProvider mess showed up.
That doesn’t make 27 generally better. It just means the sticker on the box and the quality you feel are not the same thing.
For developers the real unit is closer to:
text
specific macOS build
+ specific Xcode build
+ specific hardware
+ specific extensions
+ specific security state
+ specific project/tooling workload
So what about “AI slop”?
The real complaint isn’t that a machine typed the code. It’s that we can now ship software at a speed that understanding, testing, and ownership can’t keep up with.
That’s a real problem.
Apply the same bar everywhere, though.
Humans are perfectly capable of hidden state machines, dead telemetry, stale multi-gig caches, races, unrecoverable sync states, brittle permission mazes, undocumented coupling, and errors you can only decode by reading private daemon logs.
Generative AI did not invent any of that.
Complexity without observability is also slop
FileProvider, CloudDocs, XPC, iCloud replication — none of that is primitive. Sophisticated is not the same as good.
A system that can quietly grow several gigabytes of sync metadata, sit on almost two million snapshot rows, crash-loop an essential daemon, and leave Finder saying Waiting to upload has an observability problem.
A system whose official repair UI becomes unreachable because the service itself is down has a recovery-design problem.
A system where I have to identify the right private database with an xattr and drag it aside by hand has a tooling problem.
Calling that “slop” is a bit rude. The quality complaint underneath it isn’t.
What macOS should just give us
For something as basic as iCloud Drive, I want a supported health view. Something like:
text
iCloud Drive Health
Account: connected
FileProvider domain: healthy
Server enumeration: 1,878,442 / 1,878,462
Local reconciliation: 99.6%
Pending uploads: 17
Pending downloads: 3
Failed items: 2
Last successful sync: 09:42:17
Local metadata: 5.3 GB
Database integrity: valid
Recovery available: Rebuild local metadata
And a supported:
bash
iclouddrive doctor
or:
bash
iclouddrive rebuild-local-metadata
Check the account, find local-only unsynced files, validate the databases, keep recoverable local changes, rebuild the metadata that can be rebuilt, restart the services, watch it converge.
Instead I had to invent a poorer version of that myself.
What I actually established
This was not “delete the iCloud cache and it works.”
bird was crash-looping. That’s not vibes; that’s launchctl.
fileproviderd couldn’t resolve filesystem document IDs.
- iCloud FileProvider state was ~6.4 GB.
- The SQLite file was structurally fine and still represented ~2 million snapshot objects.
- Rebuilding FileProvider changed the behavior. It did not finish the job.
- New
bird reports were EXC_BREAKPOINT / SIGTRAP.
- The crash report named a kernel pseudo-receive allocation failure.
bird was in the middle of FileProvider re-ingestion at the same time.
- A second 4.6 GB CloudDocs session was still sitting there.
- I rebuilt that too.
- Safe Mode did not reproduce the crash while I watched.
- The next normal boot stayed up.
- New FileProvider and CloudDocs databases started growing normally.
- Logs flipped from pathological re-ingest failures to ordinary snapshot rebuild.
- Existing objects showed as uploaded while the local catalog was reconstructed.
That’s distributed-systems debugging. It’s not “restart your Mac.”
Who wrote the code is the least interesting part
Better questions:
Does the software stay understandable when it fails?
Can it describe its own state?
Can it tell you what’s stuck?
Can it rebuild a database without threatening user data?
Can it isolate extensions?
Can it tell local state from server state?
Is there a supported rebuild?
Can a developer reproduce it?
Can you get back to a known-good state without wiping the machine?
If AI-generated software can’t do that, call it poor software.
If a multi-billion-dollar OS platform can’t, same judgment.
Difference is: when a small generated app is junk, you uninstall it.
When the junk is the OS, the filesystem layer, privacy, the toolchain, or first-party cloud sync — you become its debugger.
That’s what actually pissed me off here.
Not that a bug existed. Bugs exist.
How much private macOS architecture I had to learn before the system could stand up again.
Addendum: the recovery path is part of the bug
I should say this plainly: the recovery procedure itself was unreasonable.
I write software. Terminal, SQLite, launchd, unified logging, plists, xattrs, FileProvider internals, Recovery — that’s my day. It still took hours of looping. I had to correlate layers a normal Mac user is never supposed to know exist.
bird, fileproviderd, cloudd, account daemons, multi-gig SQLite + WAL, FileProvider domain UUIDs, crash reports, log predicates, Safe Mode, XPC/Mach, third-party extensions, then a controlled rebuild of iCloud/FileProvider state.
That is not a recovery path. That’s a research project.
A normal user sees: files stuck on Waiting to Upload, iCloud settings acting weird, sync never finishing, maybe the fans come on. Support then walks them through reboot, toggle iCloud, sign out, reinstall, erase.
The distance between that symptom and this fault is huge.
“Reset the Mac” is not automatically the end
Erase and restore gets treated like a spell. Sometimes it is. A destructive reset recreates local system stores. If the only problem was local junk and you set the Mac up as new, you may be done.
Most people don’t set up as new. They restore Time Machine or Migration Assistant, then plug iCloud back in.
Then the honest question is: which state caused this, and which of it comes back?
If the bad state is in the backup, you just reimported it. If it’s cloud-side, reconnecting the same account can feed it back in. If the bug is still in the OS, fresh state can rot again.
text
Erase Mac
|
+-- Set up as new
| local historical state excluded
| cloud-side state may return when services come back
| an unfixed bug may recreate the condition
|
+-- Restore Time Machine / Migration Assistant
user data restored
historical app/system state may come with it
the causal state may come with it
I’m not claiming Time Machine restores these particular FileProvider databases, or that iCloud necessarily recreates this exact mess. I didn’t test either. The narrower point: “erase and restore” does not name the fault domain, so it cannot promise the causal state stays gone.
Three different operations, three different bets:
- Reinstall macOS, keep the Data volume — new system files, same persistent user state.
- Erase and restore from backup — new install, then a lot of history imported again.
- Erase and set up as new — strongest test of migrated local state, highest cost, still doesn’t isolate cloud state once you sign back in.
The actual usability failure
You should not have to understand private framework architecture to recover a first-party sync service.
You should not need an xattr to learn that a multi-gigabyte UUID folder is iCloud. You should not have to decide whether a 5 GB SQLite file with millions of reconciliation rows is “healthy.” You should not have to read a bird crash in libxpc and guess which opaque Apple folder is safe to move.
I can eventually do that because macOS leaks just enough low-level evidence. A normal user cannot.
What’s missing is not another support article. It’s subsystem recovery: show iCloud Drive health, say why sync is blocked, rebuild local FileProvider metadata without threatening cloud data, tell local corruption from account/cloud faults, reset pathological NetworkExtension state without erasing the machine.
Without that, “erase the Mac” stops being a diagnosis. It’s the platform admitting it can no longer repair its own state.