fileproviderd at 270% CPU: How Git Repos in Google Drive Broke macOS File Sync

My MacBook Air (M3, 8 cores, 16 GB) had been noticeably sluggish for days. Fans don’t exist on this machine, so the only signals were a warm chassis, a laggy UI and a load average that never came down. A quick look at top pointed at a process most people never think about: fileproviderd.

What followed was a few hours of digging through File Provider dumps, consistency checks and Google Drive logs. The root cause turned out to be self-inflicted: roughly 330,000 files of Git repositories, node_modules, Python venvs and Rust build output living inside the Google Drive folder. The sync database had collapsed under it.

This post covers where the errors are visible, why this setup is a bad idea, and how I moved everything out without breaking absolute paths, Claude Code sessions or Codex sessions.


The Symptom: Constant CPU Load

The first snapshot, sorted by CPU:

samuel.heinrich@ ~ % top -l 2 -n 20 -o cpu -stats pid,command,cpu,mem,time,state
Load Avg: 15.46, 17.21, 14.16
CPU usage: 55.75% user, 15.86% sys, 28.37% idle

PID    COMMAND          %CPU  MEM    TIME     STATE
1131   fileproviderd    173.2 577M+  103 hrs  running
11515  Google Drive     79.0  137M+  04:34.62 running
1111   suggestd         65.9  29M+   33:17:41 running
612    WindowServer     49.3  1729M+ 31:35:42 sleeping
0      kernel_task      17.9  32M-   17:45:13 running
samuel.heinrich@ ~ % uptime
21:58  up 8 days,  9:55, 10 users, load averages: 15.46 17.21 14.16

Two numbers stand out:

  • A load average of 15–17 on an 8-core machine.
  • fileproviderd had accumulated 103 hours of CPU time in 8 days of uptime. That is more than half a core, permanently, for a background daemon. A few minutes later it peaked at 276%.

fileproviderd is the macOS daemon behind the File Provider framework. On current macOS versions, Google Drive for desktop, OneDrive and iCloud Drive all sync through it. Files live under ~/Library/CloudStorage/, and fileproviderd keeps a local database that reconciles the file system with the provider’s cloud state.

samuel.heinrich@ ~ % ls ~/Library/CloudStorage/
GoogleDrive-
<account>@gmail.com
OneDrive-
<org>

So the question was: what is the File Provider trying to sync, and why does it never finish?


Where the Sync Errors Show Up

There are three places worth looking at. None of them are visible in the Google Drive UI, which just shows a spinning sync icon.

1. fileproviderctl dump

fileproviderctl ships with macOS. dump writes the complete daemon state, including every pending sync job:

samuel.heinrich@ ~ % fileproviderctl dump > fpdump.txt
samuel.heinrich@ ~ % wc -l fpdump.txt
 1912550 fpdump.txt

Almost two million lines. Domain and file names are obfuscated (g{26}2 (f{14}l.com)), so first find the section of the right provider:

samuel.heinrich@ ~ % grep -nE "^(com|us)\.[a-zA-Z]" fpdump.txt
9:com.apple.CloudDocs.iCloudDriveFileProvider
14291:com.apple.Photos.PhotosFileProvider
14404:us.electronic.macdroid.mountprovider
14448:com.google.drivefs.fpext
1871724:com.microsoft.OneDrive.FileProvider

Pitfall: my first quick look found 65 sync errors dating back to March 2024 and I blamed Google Drive. They belonged to the iCloud Drive domain, which comes first in the dump. Always check which provider block an error belongs to.

The Google Drive block, sync engine state:

sync engine state:
    + upload progress: ... Fraction completed: 0.9946 / Completed: 67206662327 of 67573568200
    + domain version: 3207
    + scheduling state: running
    + error generation: 6346
    + disk import: no
    + stream reset: yes
      - scheduler: <l:com.apple.fileproviderd.stream-reset ⏳  registration:<from:2026-10-03 17:29:11 +0000 count:168> ...
  • error generation: 6346: the sync engine has gone through thousands of error cycles.
  • stream reset: yes with count:168: the change stream between fileproviderd and the Google Drive extension was reset 168 times in a few hours. Every reset means re-enumerating the domain, in this case 67 GB.

The individual jobs show what is stuck. Three patterns dominated:

⬆︎⬇︎  <fs:⏳  fileID(1198164) delete:ready|recursive|parentDeleted content:watch sver:fileID(1190481)/w{2}e cver:1198164 domver:2853 ⧗recursiveDeletionBackOff> <-> <fp:✅  1462 fields:structure content:watch sver:2 cver:> dir
⬆︎   <fs:⏳  docID(379191) fields:parentID|structure content:watch sver:fileID(87316600)/0{12}1.txt cver:87316875@4:sz:2004 domver:3207 ⧗parentCreation> <-> <fp:✅  527795 content:watch sver:24 ...> doc
     modifyItem:baseVersion:changedFields:contents:options:request:completionHandler: (no timeout), no progress
  • recursiveDeletionBackOff: a local deletion that should be propagated to the cloud, now in back-off.
  • parentCreation: an item waiting for its parent folder to be created first.
  • modifyItem … no progress: calls into the Google Drive extension that never return.

Counting them in the Google Drive block:

samuel.heinrich@ ~ % grep -c recursiveDeletionBackOff fpdump.txt
56092
samuel.heinrich@ ~ % grep -c parentCreation fpdump.txt
66376

More than 122,000 stuck items. That is not a backlog that clears itself.

2. FPCK: the File Provider consistency check

fileproviderctl check runs FPCK, a read-only consistency check of the domain database against the file system. repair exists as well, but I did not use it.

samuel.heinrich@ ~ % fileproviderctl check -P -v \
    -a "$HOME/Library/CloudStorage/GoogleDrive-
<account>@gmail.com" -o fpck.txt
💣 FPCK failed completing: Error Domain=FPCKDomain Code=65 "(null)"

The check itself aborted. The partial report still says enough:

numberOfBrokenFilesInFSAndFSSnapshotCheck: 140000
numberOfBrokenFilesInReconciliationTableCheck: 36000
numberOfBrokenFilesInFSSnapshotAndFPSnapshotCheck: 110
pendingSetErrors: {"FPCKPendingSetInternalErrorDomain;8":[{"count":55000,"direction":1, ...
db_error_retry_count: 233

About 140,000 inconsistencies between the file system and the database snapshot, 36,000 in the reconciliation table, 55,000 in the pending set. The database is beyond saving.

3. Google Drive’s own log

Google Drive writes a plain-text log:

samuel.heinrich@ ~ % ls ~/Library/Application\ Support/Google/DriveFS/Logs/
drive_fs.txt  structured_log_...  structured_log_global ...

On startup it lists previous crash reports:

drive_fs_main.cc:221:LogExistingCrashReports 2026-09-29T01:13:52.000Z uuid=03b1... uploaded=1
drive_fs_main.cc:221:LogExistingCrashReports 2026-09-29T08:55:40.000Z uuid=b527... uploaded=1
drive_fs_main.cc:221:LogExistingCrashReports 2026-09-29T09:49:24.000Z uuid=0a3a... uploaded=0
...

Grouped by day:

samuel.heinrich@ ~ % grep LogExistingCrashReports drive_fs.txt | awk '{print substr($4,1,10)}' | sort | uniq -c
   1 2026-09-15
   2 2026-09-16
   3 2026-09-27
   5 2026-09-28
   6 2026-09-29
   2 2026-09-30
   5 2026-10-01

24 crashes in less than three weeks, recently up to six per day. Each crash tears down the extension, and fileproviderd answers with a stream reset. That explains the 168 resets.

The most frequent error over 30 minutes:

2128 change_handler.cc:N:PopulateTimeChange Invalid timestamps requested: Is create request: false,
     Create: false, Modification: false, Last used: true

These are modify requests in which only the last used date changed. Most likely a local process opened the files (Spotlight, Finder and suggestd were all busy), the timestamp change became a sync job, and Google Drive rejected it. More noise on a queue that is already stuck.

Later, under load, the log also showed hung threads and stalled transfers:

crashpad_thread_watcher_listener.cc:35:ThreadsStuck One or more threads appear to be stuck. Capturing a dump ...
curl_api.cc:N:StatusFromCurlCode Remapped curl code 28 to drive::ds::Status::TIMEOUT_EXCEEDED: Operation too slow.
absl_status_utils.cc:N:UNKNOWN INTERNAL: Unknown Apiary reason [conditionNotMet]. Location was [drive.googleapis.com].

The network was fine (21 MB/s to Google in a parallel test). The client simply could not keep up with its own queue.


Root Cause: 330,000 Files That Never Sit Still

The stuck items pointed to one folder: My Drive/0004_git, where all my Git repositories lived. Counting what was in there:

samuel.heinrich@ ~ % cd ~/Library/CloudStorage/GoogleDrive-</account>
<account>@gmail.com/My\ Drive
samuel.heinrich@ My Drive % python3 dataless.py 0004_git
files=328946 dirs=23945 dataless_files=23273 dataless_dirs=0 local_size=80.4GB
0004_git: .git=32  node_modules=30  .venv=7
files in node_modules:  119042

The biggest offenders:

Path Size Files
public/transferbuddy/target (Rust build output) 57.2 GB 155,091
videos/.../_audio_analysis/.venv 1.1 GB 22,574
public/globivonnairobi/node_modules 535 MB 30,496
13 × identical node_modules in video projects (~5,300 files each) ~1 GB ~69,000
public/netmon/.build (Swift) 312 MB 2,000

Why this breaks a File Provider

Google Drive is designed for documents. A file is created, edited a few times, maybe renamed. Each of those events becomes exactly one sync job.

Development folders behave completely differently:

  • npm install / pnpm install creates and deletes tens of thousands of small files in seconds.
  • cargo build rewrites target/debug/incremental/* on every build. Old session directories are deleted and new ones created.
  • git checkout, git gc and git fetch replace objects and pack files.
  • Python venvs are recreated wholesale.

For fileproviderd, every one of these operations is a separate create, modify or delete job that has to go through the Google Drive extension, to the Drive API and back. None of this content needs to be in the cloud: it can be regenerated, or it already lives on GitHub/GitLab.

Once the backlog is large enough, a feedback loop starts:

flowchart TD
    DEV[npm install / cargo build / git checkout]
    FS[Tens of thousands of FS events]
    FPD[fileproviderd queues sync jobs]
    EXT[Google Drive extension overloaded]
    CRASH[Drive crashes or threads hang]
    RESET[Stream reset: re-enumerate 67 GB]
    STUCK[Jobs pile up in back-off]

    DEV --> FS
    FS --> FPD
    FPD --> EXT
    EXT --> CRASH
    CRASH --> RESET
    RESET --> FPD
    FPD --> STUCK
    STUCK --> EXT

The result was 122,000 stuck jobs, 168 full re-enumerations per day, 24 crashes and a corrupted database. Once you reach that state, the loop doesn’t end by itself.


Side Quest: Why “Empty Trash” Hung Forever

The move required free disk space: 15 GB free on a 460 GB volume. The obvious first step, emptying the trash, hung in Finder’s “Emptying the Trash…” dialog, which couldn’t be cancelled.

The user trash itself was harmless: 49 items, 38 GB, mostly firmware images, nothing locked or open. The cause was elsewhere. Google Drive’s File Provider domain has its own trash:

samuel.heinrich@ ~ % ls -lt ~/Library/CloudStorage/GoogleDrive-</account>
<account>@gmail.com/.Trash | head -4
drwx------@     2 samuel.heinrich  staff        64 Oct  2 21:42 macos-native-0.2.8
drwx------@ 65535 samuel.heinrich  staff        64 Oct  2 17:14 s-hmu3463xf3-1ntmumx-di73p4v96vw4wixvc8iy63fe2
drwx------@ 65535 samuel.heinrich  staff   2097120 Oct  2 14:31 s-hmu31pp2kg-07mi54r-eicpiaeekeyp1yemxpe2kgjgc

Rust incremental compilation sessions (s-…), .rlib files and Git pack files, all from the same repository folder. Finder’s Empty Trash also empties the File Provider trashes. Each deletion there has to go through the broken fileproviderd database, so the dialog waits forever.

The workaround was to empty only the local trash, bypassing Finder, and then relaunch Finder to get rid of the dialog:

samuel.heinrich@ ~ % find ~/.Trash -mindepth 1 -maxdepth 1 -exec rm -rf {} +
samuel.heinrich@ ~ % df -h /System/Volumes/Data
/dev/disk3s5   460Gi   375Gi    54Gi    88%    2.6M  562M    0%   /System/Volumes/Data
samuel.heinrich@ ~ % killall Finder

I emptied the Google Drive trash on drive.google.com. That is a single server-side operation.


The Fix, Step by Step

The goal:

  • Move My Drive/0004_git to ~/0004_git.
  • Keep everything working that references the old absolute path: scripts, configs, Claude Code and Codex sessions.
  • Throw away the corrupted sync database and start with a clean one.
flowchart LR
    A[Inventory] --> B[Delete build dirs]
    B --> C[Download cloud-only files]
    C --> D[Copy + verify]
    D --> E[Rewrite paths]
    E --> F[Delete folder on web]
    F --> G[Disconnect / reconnect Drive]
    G --> H[Symlink old path]

Step 1: Inventory, and the dataless trap

With File Provider, files can be dataless: a placeholder with metadata but no local content. ls -lO shows the flag:

samuel.heinrich@ ~ % ls -lO .../0004_git/private/netdash/.git/HEAD
-rw-r--r--@ 1 samuel.heinrich  staff  compressed,dataless 21 Sep  4 10:00 .../netdash/.git/HEAD

To move or copy such a file, macOS has to download it first through the provider. If the provider is unhealthy or not running, the copy hangs or fails. So check before you move anything. SF_DATALESS is 0x40000000 in st_flags:

import os, sys
DL = 0x40000000
files = dl = 0
for dp, dn, fn in os.walk(sys.argv[1]):
    for f in fn:
        files += 1
        if os.lstat(os.path.join(dp, f)).st_flags & DL:
            dl += 1
print(f"files={files} dataless={dl}")

The result: 23,273 dataless files (7.2 GB) and 80.4 GB of local data, with 54 GB free. A copy was impossible, and a move would have stalled on the placeholders.

Step 2: Delete what can be regenerated

Most of the dataless data (4.1 GB) and most of the file count sat in build directories. I deleted every target, node_modules, .venv/venv and .build directory that contained dataless files. Each one was verified first by a marker file: Cargo.toml next to target, package.json next to node_modules, pyvenv.cfg inside a venv, Package.swift next to .build.

OK  57190.4MB 155091 files ( 3994 cloud)  public/transferbuddy/target
OK   1125.5MB  22574 files ( 2674 cloud)  videos/.../_audio_analysis/.venv
OK    535.0MB  30496 files ( 2504 cloud)  public/globivonnairobi/node_modules
OK    311.9MB   2000 files (  243 cloud)  public/netmon/.build
...
34 directories
Before After
Files in 0004_git 328,946 15,050
Local size 80.4 GB 23.0 GB
Free disk space 54 GB 116 GB
Dataless files 23,273 1,557 (2.6 GB)

Step 3: Download the remaining cloud-only files

The 1,557 remaining placeholders were real content: videos, audio, 3D models, presentations and some Git objects. Reading a file forces the File Provider to materialize it.

The first attempt made no progress for 30 minutes. The log explained why: I had quit Google Drive earlier, but it had been relaunched in the background. When I opened it again, it only logged a double launch:

DFSAppDelegate.mm:287:-[DFSAppDelegate applicationShouldHandleReopen:hasVisibleWindows:] Got double launch
crashpad_thread_watcher_listener.cc:35:ThreadsStuck One or more threads appear to be stuck.

It was still pushing the deletions from step 2 to the cloud and had stopped processing downloads. After force-quitting and restarting Drive, a parallel read with a per-file timeout worked:

def get(p):
    subprocess.run(["cat", p], stdout=subprocess.DEVNULL, timeout=900)
    return p, not (os.lstat(p).st_flags & 0x40000000)

with ThreadPoolExecutor(16) as ex:
    for p, ok in ex.map(get, paths):
        ...
finished ok=1539 bad=6

Four tiny files stayed dataless even though cat returned their content. Two large videos timed out. More on that below.

Step 4: Copy instead of move, then verify

With 116 GB free, copying was now the safer option: the original stays untouched until the copy is verified. ditto preserves permissions, extended attributes and timestamps:

samuel.heinrich@ ~ % ditto ".../My Drive/0004_git" ~/0004_git

ditto stalled after 541 MB of a 1.2 GB video. I resumed with a per-file loop that skips files already copied (same size and mtime) and runs a ditto per file with a timeout. That surfaced two gotchas:

  • Dangling symlinks: pnpm workspaces use symlinks into the root node_modules, which I had just deleted. ditto refuses them (Cannot get the real path for source). I recreated them with ln -s "$(readlink src)" dst.
  • ditto follows a symlink passed as the source argument. Per-file copying turned 11 symlinks, such as pnpm workspace links and Versions/Current inside a .framework, into real directories. I replaced them with the original symlinks afterwards.

Verification compared every entry, checked for leftover placeholders and ran git fsck on every repository:

source entries=15050 missing=3 size_mismatch=0 dataless_in_copy=0 extra_in_copy=0
  MISSING clones/ftpmap/__MACOSX/MacOS/._.DS_Store
  MISSING clones/ftpmap/__MACOSX/MacOS/build/._.DS_Store
  MISSING videos/.../00_Network_Engineers_4k_20260929T103833203Z.mp4
samuel.heinrich@ 0004_git % find . -name .git -not -path "*/node_modules/*" | while read g; do
    git -C "$(dirname "$g")" fsck --no-dangling --connectivity-only >/dev/null && echo "OK $(dirname "$g")"
done
OK ./arduino/c6-huso/third_party/esp32-doom
OK ./clones/certctl
...
OK ./web/kisound

All 32 repositories passed git fsck. The two ._ files are AppleDouble leftovers from an extracted ZIP archive, which ditto presumably folded into extended attributes. The only real loss was one rendered 4K video, which can be regenerated. One stuck .gitignore I restored with git checkout -- docugenerator/.gitignore.

Step 5: Rewrite absolute paths

The old path appeared in more places than expected:

Location References
Claude Code project dirs ~/.claude/projects/ 18 dirs, 24 sessions
~/.claude.json (project settings, trust) 13 projects
~/.claude/history.jsonl (prompt history) 522 entries
Codex sessions ~/.codex/sessions/**/*.jsonl 33 files
~/.codex/config.toml ([projects."…"] trust) 11
~/.codex/history.jsonl, .codex-global-state.json 2
~/.zshrc (source …/kisound-render.zsh) 1
~/.gitconfig (safe.directory) 3
Code, docs, manifests 210 in 60 files

Before touching anything, I backed up all affected files to ~/path-migration-backup-20261004/. I also quit Codex completely: its background app-server daemon keeps state in memory and would have overwritten the changes.

Claude Code stores sessions in a directory named after the working directory, with every non-alphanumeric character replaced by -:

/Users/samuel.heinrich/Library/CloudStorage/GoogleDrive-</account>
<account>@gmail.com/My Drive/0004_git/blog/show-run.ch
-> -Users-samuel-heinrich-Library-CloudStorage-GoogleDrive-</account>
<account>-gmail-com-My-Drive-0004-git-blog-show-run-ch

/Users/samuel.heinrich/0004_git/blog/show-run.ch
-> -Users-samuel-heinrich-0004-git-blog-show-run-ch

The migration renamed the directories and replaced both the plain path ("cwd":"…") and the encoded directory name inside the session files. ~/.claude.json was rewritten only after checking that no new project key would collide with an existing one, and every JSON, JSONL and TOML file was parsed again before it was written back.

In the code there were three variants of the old path, all mapped to /Users/samuel.heinrich/0004_git:

/Users/samuel.heinrich/Library/CloudStorage/GoogleDrive-</account>
<account>@gmail.com/My Drive/0004_git
/Users/samuel.heinrich/Library/CloudStorage/GoogleDrive-</account>
<account>@gmail.com/My%20Drive/0004_git
/Users/samuel.heinrich/Google Drive/My Drive/0004_git     (pre-File-Provider legacy path)

A final check confirmed that 65 of 66 known project and working directories exist at the new location. The missing one was inside a node_modules folder.

Step 6: Delete the folder on the web, then reset the sync database

Deleting 15,000 files locally would have sent them through the broken database again. Deleting the folder on drive.google.com is a single server-side operation, and it stays in the Drive trash for 30 days as an extra backup.

Then Settings → Disconnect account. Drive first checks for unsynced files:

Save unsynced files?
You still have 101 files syncing. Disconnecting might result in losing 101 offline files.
101 unsynced files, 0 bytes

Before confirming, I checked that no local, non-placeholder file outside the old repo folder had changed in the last 7 days. Only .DS_Store files had. The export of the “unsynced files” failed, and the log shows why:

cello_shim.cc:453:CopyPendingUploadItemInternal Failed to copy file to destination:
  .../Google Drive (Not synced)/Meine Ablage/0004_git/public/transferbuddy/target/debug...
 110 0004_git/public/transferbuddy/target/debug
  92 0004_git/public/globivonnairobi/node_modules/.pnpm
   0 anything else

They were all pending uploads from the build directories deleted in step 2, so Delete unsynced files was the right choice. The app then hung on “syncing”, so I force-quit it. Afterwards the domain was gone and fileproviderd dropped to idle:

samuel.heinrich@ ~ % for i in 1 2 3 4 5 6; do sleep 10; echo "$(date +%T) fileproviderd: $(ps -o %cpu= -p $(pgrep -x fileproviderd))%"; done
09:22:48 fileproviderd:   0.0%
09:22:58 fileproviderd:   0.0%
09:23:09 fileproviderd:   0.0%
09:23:19 fileproviderd:   0.0%
09:23:29 fileproviderd:   0.0%
09:23:39 fileproviderd:   0.0%

macOS kept the old local content in a preserved folder, . It contained 634 files, mostly fragments of the old repository folder. By the time I signed in again, the folder had been emptied and marked with .drive_fs_ignore_preserved_domain, and the Drive log reported:

file_provider_activity_monitor.cc:618:NotifyReimportCompleted Reimport completion initiated by the system received for item id: root
client.cc:1653:operator() No preserved domains found.

Spot checks confirmed that the files from the preserved folder exist in the new domain.

Step 7: A symlink for the old path, tested first

I wanted the old path to keep working as a safety net. Before pointing a symlink at 23 GB of repositories, I tested how Google Drive treats symlinks with a dummy:

samuel.heinrich@ ~ % mkdir ~/symlinktest-gdrive && echo test > ~/symlinktest-gdrive/hello.txt
samuel.heinrich@ ~ % ln -s ~/symlinktest-gdrive ".../My Drive/_symlinktest"

In the File Provider dump, the link shows up as a single lnk item of 41 bytes, which is the length of the target path. It is synced on both sides, and hello.txt appears nowhere:

<fs:✅  fileID(104459974) ... sver:fileID(104456159)/_{10}t ...> <-> <fp:✅  13257 ...> symlink
<s:fileID(104459974) p:fileID(104456159) n:"_{10}t" lnk sz:41 m:rwx ...>

Google Drive stores the symlink itself and does not follow it. Then the real link:

samuel.heinrich@ ~ % ln -s /Users/samuel.heinrich/0004_git ".../My Drive/0004_git"
samuel.heinrich@ ~ % ls -la ".../My Drive/0004_git"
lrwxr-xr-x@ 1 samuel.heinrich  staff  31 Oct  4 09:29 .../My Drive/0004_git -> /Users/samuel.heinrich/0004_git

Before vs. After

Before, with the old domain:

Load Avg: 15.46, 17.21, 14.16

PID    COMMAND          %CPU  MEM    TIME     STATE
1131   fileproviderd    173.2 577M+  103 hrs  running
11515  Google Drive     79.0  137M+  04:34.62 running

After, with the new domain, signed in, and folders being made available offline in the background:

load averages: 5.88 5.05 5.02

PID    COMMAND          %CPU TIME     STATE
612    WindowServer     37.5 33:30:19 sleeping
81473  Google Chrome He 18.0 08:18.03 running
84553  Google Drive     11.4 03:08.52 sleeping
1575   Terminal         9.8  53:27.59 sleeping
0      kernel_task      8.4  21:35:03 running

fileproviderd no longer appears in the top 8.

Metric Before After
Load average (8 cores) 15–17 ~5
fileproviderd CPU 170–276% not in top 8 (0.0% while no domain was active)
Google Drive CPU 80–100% ~11%
error generation 6,346 3
Stream resets 168 in a few hours none
Stuck deletions (recursiveDeletionBackOff) 56,092 0
FPCK inconsistencies ~140,000 fresh database
Files from 0004_git in Drive 328,946 1 symlink
Free disk space 15 GB 121 GB

While the new domain was downloading folders I had marked available offline, fileproviderd briefly went up to ~95% again. That is expected during an initial download and drops back down afterwards. The difference is that the work now has an end.


Conclusion

The File Provider framework works well for what Google Drive is built for: documents. It is the wrong place for development folders. Every npm install, cargo build or git checkout becomes thousands of sync jobs. At some point the extension crashes, fileproviderd resets the stream, and the database corrupts under a backlog it can never finish.

What I take away from this:

  • Code belongs in Git, not in a sync client. Keep repositories in a local folder such as ~/dev or ~/0004_git and back them up through GitHub/GitLab and Time Machine.
  • fileproviderctl dump and fileproviderctl check reveal what the sync UI hides. Look for error generation, stream reset, recursiveDeletionBackOff and parentCreation, and check which provider block they belong to.
  • Check for dataless files (ls -lO, st_flags & 0x40000000) before moving anything out of ~/Library/CloudStorage/.
  • Delete large folders on the web, not locally, when the local client is already struggling.
  • A corrupted domain doesn’t recover by itself. Disconnecting and reconnecting the account is the clean reset.
  • Absolute paths are everywhere, including AI tooling. Claude Code encodes the working directory in its project directory names, and Codex stores it in every session file. Back them up and quit the apps before rewriting.
Samuel Heinrich
Senior Network Engineer at Selution AG (Switzerland)
Arbeitet in Raum Basel (Switzerland) als Senior Network Engineer mit über 15 Jahren Erfahrung im Bereich Netzwerk

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.