Meine KI-App stürzte auf einem 4.000€ MacBook ab. Der Code war einwandfrei.
Meine App crasht. Zufällige Crashes, die schlimmste Sorte. Sie stirbt wie ein Goldfisch, den man morgens tot im Wasser treibend findet – ohne jede Erklärung. Fünfzehn Minuten Build-Zeit auf einem 4.000-Euro-MacBook. Der Code kompiliert. Tests laufen durch. Und trotzdem: next: command not found.
Zwei Tage lang beschuldigte Claude Next.js, Turbopack, Node, npm, das Wetter. Ich las Logs wie ein mittelalterlicher Mönch beim Abschreiben heiliger Schriften. Nichts. Der Übeltäter versteckte sich in macOS selbst, in etwas, woran kein Entwickler denkt: iCloud Drive. Jeder Reparaturversuch machte das Problem exponentiell schlimmer.
TLDR: Wenn deine Projekte in ~/Documents/ liegen, behandelt iCloud node_modules wie Urlaubsfotos und löscht willkürlich Dateien. Jeder "clevere" Fix macht es schlimmer. Die echte Lösung ist ein einziger Befehl. Dieser Artikel erspart dir zwei Tage.

Und was besonders ärgert: Mein Entwicklungsprozess ist solide. Ich baue mit Prompt-Verträgen, die AI-Coding von Glücksspiel zu Shipping verwandeln. Der Code war getestet, strukturiert, dokumentiert. Das bedeutete, das Problem musste ganz woanders liegen.
Die App, die sich weigerte zu laufen
Es begann an einem Dienstag. Der Next.js-Dev-Server startete, kompilierte eine Weile, dann starb er. Manchmal nach 30 Sekunden. Manchmal nach 10 Minuten. Manchmal lief er eine Stunde problemlos und crashte dann mitten im Hot Reload.
Kein Muster. Kein reproduzierbarer Auslöser. Einfach nur Tod.
Turbopack beschwerte sich über fehlende Module. Dateien, die laut ls eindeutig existierten, verschwanden mitten in der Kompilierung. Ich startete neu, alles funktionierte, dann crashte es wieder beim Testen einer Komponente.
Ich tat, was jeder Entwickler tut: beschuldigte das Framework. Löschte .next. Löschte node_modules, führte npm install aus. Prüfte die Turbopack-Config. Downgrade. Upgrade. Nichts half dauerhaft.
Dann, aus purer Verzweiflung, schloss ich VS Code und öffnete den Finder.
Der Bug war nicht im Code. Er war nicht mal im Terminal.
Die unsichtbare Zwangsräumung
Kleine Cloud-Icons. Auf Dateien in node_modules.
<figure data-source="image">

iCloud Drive räumte JavaScript-Dateien aus meinen Dependencies zwangs. Entfernte echten Quellcode von der Festplatte und ersetzte ihn durch Cloud-Platzhalter zur "Speicheroptimierung". Mein node_modules-Ordner wurde wie eine Urlaubsfoto-Galerie behandelt: hochgeladen, dann lokal aufgeräumt, weil ich sicher nicht all diese Dateien auf meiner Maschine brauchte.
Warum? Meine Projekte lagen in ~/Documents/dev/. Unter macOS wird ~/Documents/ standardmäßig mit iCloud Drive synchronisiert. Jede Datei dort ist Freiwild.
Der bekannte Fix ist das .nosync-Suffix-Pattern:
mv node_modules node_modules.nosync
ln -s node_modules.nosync node_modules
Den echten Ordner umbenennen, damit iCloud ihn ignoriert, einen Symlink erstellen, damit Node.js ihn trotzdem am erwarteten Pfad findet.
Fix angewendet. Server neugestartet. Dashboard geladen.
Problem gelöst. Am nächsten Morgen war alles wieder kaputt.
Der Abstieg: Fünf Fixes, die alles schlimmer machten
Morgenkaffee. Terminal öffnen. next: command not found. Der Symlink war weg. Nicht der Ordner, der Ordner war da, intakt. Nur der Symlink war verschwunden.
Neu erstellt. Server gebootet. Fünfzehn Sekunden später: Crash. Symlink weg.
Da bemerkte ich:
$ ls | grep node_modules
node_modules 3
node_modules 4
node_modules 5
node_modules 6
node_modules 7
node_modules 8
node_modules.nosync
iCloud löschte meinen Symlink nicht. Es benannte ihn um. Konflikt mit irgendeinem Server-seitigen Geist erkannt, gelöst durch Anhängen einer Nummer an die lokale Version. Am Ende des Tages: node_modules 20.
Was folgt, sind fünf Versuche, das zu reparieren. Jeder cleverer als der letzte. Jeder machte es schlimmer. Ein echter Abstieg in den Wahnsinn, wie eine dieser Horrorgeschichten, wo jede Tür, die du öffnest, zu einem kleineren Raum führt.
Fix 1: Die nummerierten Kopien aufräumen. Offensichtlich füttern die Duplikate die Schleife. Entfernen, Problem weg. Funktionierte 20 Sekunden. Dann erschien node_modules 9. Der Server-seitige Eintrag war noch da.
Fix 2: Extended Attributes zum Ausschluss von der Sync. macOS hat Extended Attributes (xattrs), die steuern, wie der File Provider mit Dateien umgeht. Ich markierte den Symlink als ausgeschlossen:
xattr -w com.apple.bird.metadata '{"excludeFromSync":true}' node_modules
xattr -w com.apple.fileprovider.ignore 1 node_modules
Das ist der Fix, der alles richtig kaputt machte. Statt zufälligem Verschwinden verschwand der Symlink jetzt in exakt 15 Sekunden. Jedes. Einzelne. Mal. Als hätte ich eine Zielscheibe darauf gemalt.
Fix 3: Immutable Flag. chflags uchg macht eine Datei unlöschbar. Sicher kann nichts das Dateisystem selbst überschreiben?
iClouds File Provider Daemon läuft mit erhöhten Rechten. Umging das Immutable Flag, erstellte node_modules 19, entfernte das "geschützte" Original. (So viel dazu.)
Fix 4: node_modules komplett außerhalb von iCloud verschieben. Die echten Dateien in ~/Library/ (nicht synchronisiert), Symlink zeigt dorthin. Logisch.
Crashte trotzdem. iCloud kümmert sich nicht darum, wohin ein Symlink zeigt. Es verwaltet den Symlink selbst, weil der Symlink in einem synchronisierten Verzeichnis liegt. Sicheres Ziel, unsicherer Link.
Fix 5: Watchdog-Script. Eine Bash-Schleife, die den Symlink alle 2 Sekunden neu erstellt. Pflaster. Turbopack wirft FATAL, wenn node_modules mitten in der Kompilierung verschwindet. Zwei Sekunden sind eine Ewigkeit für einen Bundler.
Jeder "clevere" Fix gab iCloud einen weiteren Grund zum Eingreifen.
<figure data-source="infographic">

Das Nachbarprojekt funktionierte einwandfrei
Nachdem ich jede clevere Idee ausgeschöpft hatte, tat ich, was ich zuerst hätte tun sollen: verglich mein kaputtes Projekt mit einem, das funktionierte.
Ein anderes Projekt saß im exakt gleichen ~/Documents/dev/-Ordner. Gleiches .nosync + Symlink-Pattern. Nie einen einzigen Konflikt gehabt.
Ich führte xattr -l auf beiden aus:
com.apple.fileprovider.dir#N: 1
com.apple.provenance:
com.apple.bird.metadata: {"excludeFromSync":true}
com.apple.fileprovider.dir#N: 1
com.apple.fileprovider.ignore: 1
com.apple.provenance:
Zwei zusätzliche Attribute. com.apple.bird.metadata und com.apple.fileprovider.ignore. Exakt die, die ich in Fix 2 hinzugefügt hatte.
Das gesunde Projekt hatte nichts Besonderes. Es war nur nicht "geschützt" worden.
Ein Befehl: xattr -c node_modules
xattr -c node_modules
ALLE benutzerdefinierten Extended Attributes löschen. iCloud den Symlink als langweilige, unauffällige Datei behandeln lassen.
Aber xattrs allein zu löschen war nicht das Ende. iClouds Server hatte noch das ursprüngliche node_modules-Verzeichnis von vor dem .nosync-Setup. Dreißig Minuten später lud es diese alte Kopie herunter und überschrieb meinen Symlink. Der Geist war noch auf dem Server.
Die vollständige Bereinigung:
mv node_modules node_modules_purge.nosync
ls -la node_modules # sollte "No such file" sagen
ln -s node_modules.nosync node_modules
rm -rf node_modules_purge.nosync
Das Warten ist wichtig. Überspring es und iCloud hat die Löschung noch nicht synchronisiert. Dein frischer Symlink kollidiert mit der Server-Kopie. Zurück zur Schleife.
Nach der vollständigen Bereinigung: der Server hielt stand. Fünf Minuten. Dreißig Minuten. Eine Stunde.
Hier der Mechanismus (Apple dokumentiert das nicht, also ist es aus dem Verhalten reverse-engineered): iClouds File Provider überwacht synchronisierte Verzeichnisse. Eine Datei mit nicht-standardmäßigen xattrs wird als "lokal modifiziert" markiert. Das löst einen Sync-Zyklus aus, der lokal vs. Server vergleicht. Wenn der Server einen anderen Eintrag mit dem gleichen Namen hat, Konflikt erkannt, lokale Datei umbenannt. Die umbenannte Datei trägt noch die benutzerdefinierten xattrs, was einen weiteren Sync auslöst. Schleife. Ohne benutzerdefinierte xattrs sieht iCloud den Symlink als unverändert und ignoriert ihn komplett.
Der beste Schutz vor iCloud ist, seine Aufmerksamkeit nicht zu erregen.
Deine AI-App ist nur so gut wie das OS darunter
Das ärgert mich. Wir sind besessen von Prompt Engineering, Modellauswahl, Framework-Benchmarks. Wir vergleichen Turbopack vs. Webpack wie einen heiligen Krieg. Und währenddessen räumt das Betriebssystem darunter still unsere Dependencies zwangs, weil es denkt, node_modules sei ein Fotoalbum.
AI-Apps sind dem mehr ausgesetzt als normale Web-Apps. Mehr Dateien (Agents brauchen Tooling, Embeddings, Model-Configs). Mehr Dateisystem-Churn (Hot Reload-Zyklen, Cache-Regenerierung). Mehr Dinge, die wie "große Ordner voller Zeug, das iCloud optimieren sollte" aussehen. Wenn dein AI-Projekt node_modules plus einen Vector Store plus Model-Artefakte hat, sieht iCloud eine Mise en Place von Dateien, die es hilfsbereit für dich verwalten kann.
Fünf Regeln, die mir zwei Tage erspart hätten:
Immer .nosync + Symlink für node_modules. Automatisieren. Ein Wrapper in .zshrc, der nach jedem npm install läuft, den Ordner umbenennt, den Link neu erstellt. Nicht verhandelbar, wenn deine Projekte in ~/Documents/ sind.
Nie xattrs in iCloud-Verzeichnissen anfassen. Kein com.apple.bird.metadata. Kein com.apple.fileprovider.ignore. Keine cleveren Attribute. Sie schützen Dateien nicht vor iCloud. Sie malen eine Zielscheibe darauf.
Wenn rm -rf hängt, nutze mv mit .nosync. mv node_modules old_nm.nosync ist instant auf APFS. Ohne .nosync im neuen Namen beginnt iCloud, den umbenannten Ordner hochzuladen. Hunderte Megabytes node_modules umsonst synchronisiert. (Und nie mv nach /tmp, anderes Volume, löst eine Kopie aus.)
Lass .next als echtes Verzeichnis. Turbopack kann keine Symlinks für seinen Cache handhaben. Wenn iCloud .next 2 oder .next 3 erstellt, lösche die nummerierten Kopien, erstelle keinen Symlink.
Oder zieh einfach aus iCloud raus. mv ~/Documents/dev ~/dev. Dieser Pfad wird nicht synchronisiert. Nuklear-Option, permanenter Fix. Wahrscheinlich was ich von Anfang an hätte tun sollen, statt zwei Tage Whack-a-Mole mit einem System-Daemon zu spielen.
Zwei Tage den Bach runter, die Art, wo man den Laptop in den Pool schleudern möchte. Und ich sitze in der Sonne, WiFi kriecht wie ein dreibeiniger Hund unter Beruhigungsmitteln.
Der Code war solide. Das Framework richtig konfiguriert. Es funktionierte gestern (das berühmte "es funktionierte gestern"). Irgendein System-Service, gebaut um die erbärmlichen Urlaubsfotos von Leuten zu synchronisieren, die denken, "die Cloud" sei magischer Speicher. Nicht für Dev. Definitiv nicht für Dev. Und Apple mit ihrer zwanghaften Geheimniskrämerei darüber, wie das alles unter der Haube funktioniert...
Der Fix war ein Befehl. Aber Claude Code fand ihn erst, nachdem es fünf "Lösungen" durchgebrannt hatte, die alles schlimmer machten. Jeder Versuch, meine Dateien zu schützen, gab iCloud einen weiteren Grund, sie anzugreifen.
Wenn deine App auf einem Mac läuft und deine Projekte in ~/Documents/ sitzen, prüf nach. Nicht deinen Code. Nicht deine Deps. Deine Extended Attributes. Denn macOS wurde nicht für dich designed. Es wurde für Karen aus der Buchhaltung designed.
PS: Ich habe meine eigene Urlaubsfoto-Sync schon lange deaktiviert. Nur so gesagt. 😏
Quellen: Apples File Provider Dokumentation (die praktischerweise nichts über xattr-Konfliktverhalten sagt). Das .nosync-Pattern ist community-dokumentiert, aber nicht offiziell von Apple unterstützt.
(*) Das Cover ist AI-generiert. iCloud war damit beschäftigt, das echte zwangszuräumen. 🤷