Dasselbe Repository, derselbe Commit, dieselbe package-lock.json: Auf dem einen Rechner läuft die Angular-App einwandfrei, auf dem anderen stirbt sie sofort beim Bootstrap mit einem NG0203-Fehler. Am Ende war weder Angular schuld noch npm — sondern ein Ordner namens rene.poepperl.000.
Getestet mit: Angular 22.0.8 · @angular/build 22.0.7 · Node 24 · Windows · Vite Dev-Server
Fehler NG0203 trotz fehlerfreiem Quellcode
Seit vergangenem Freitag hat mich dieses Phänomen in den Wahnsinn getrieben. Auf meinem Entwicklungsrechner bootete die Angular-App ohne Probleme, auf dem Entwicklunsserver im Development-Modus (Windows Server mit Remote Desktop) erschien nur eine weiße Seite und in der Browserkonsole folgende Fehlermeldung:
ERROR RuntimeError: NG0203: The `EnvironmentInjector` token injection failed.
`inject()` function must be called from an injection context…
at injectInjectorOnly (_pending_tasks-chunk.mjs:667:11)
at ɵɵinject (_pending_tasks-chunk.mjs:684:40)
at Object.factory (_debug_node-chunk.mjs:10034:42)
at R3Injector.hydrate (_pending_tasks-chunk.mjs:1314:11)
at __spreadProps.getStandaloneInjector (_debug_node-chunk.mjs:10054:31)
at createRootViewInjector (_debug_node-chunk.mjs:8994:44)
at ComponentFactory.create (_debug_node-chunk.mjs:9065:32)
Was bedeutet Fehler NG0203 normalerweise?
Der Fehler entsteht, wenn man die inject()-Funktion von Angular außerhalb einen gültigen Injection-Kontextes verwendet. Es geht also (eigentlich) um die Dependency Injection von Angular.
Gültige Injection-Kontexte sind:
- Klassen-Konstruktoren
- Feld-Initialisierer
- Factory-Funktionen: Innerhalb der factory-Funktion eines InjectionToken oder bei der Konfiguration von Providern mittels useFactory
- Funktionale Router-Guards & Resolver (CanActivateFn oder ResolveFn…)
Ein Blick in main.ts, app.config.ts und die verschiedenen Komponenten zeigte jedoch, dass alles sauber war. Standard-Setup mit provideRouter & Co. Nichts verdächtiges.
Wenn derselbe Code auf Rechner A funktioniert und auf Rechner B nicht, ist der Code selten das Problem.
Schritt 1: Das Wichtigste zuerst: Den Suchraum verkleinern
Bevor du stundenlang Code liest: Der Angular-Dev-Server (Vite mit On-the-fly-Modulen) und der Produktions-Build (esbuild mit festen Bundles) arbeiten völlig unterschiedlich.
Führe diesen Befehl aus:
npx ng build --configuration development
npx http-server dist/DeinProjekt/browser
Dieser Befehl umgeht den eingebauten Angular-Vite-Dev-Server, erstellt einen Build und liefert ihn in einem einfachen http-server aus. Wenn das funktioniert, liegt es definitiv nicht am Code oder den Abhängigkeiten, sondern irgendwo im Vite-Dev-Server.
Schritt 2: Modulgraph analysieren
Die Fehlermeldung NG0203 deutet daraufhin, dass an der Stelle an der inject aufgerufen wird, wider Erwarten doch kein Injection-Kontext besteht, und dass wiederum kann durch ein Multi-Instanz-Problem verursacht werden. Wenn der Dev-Server den Angular-Core mehrfach lädt anstatt nur einmal, dann wird beim ersten Laden der Injection-Kontext erzeugt, aber in der zweiten Instanz wird das inject aufgerufen – ohne Injection-Kontext. Und dann kracht es.
Die Fehlersuche sollte also im Netzwerk-Tab des Browser-DevTools weitergehen um hier Gewissheit zu bekommen.
In meinem Fall lieferte der Dev-Server tatsächlich die Module / Modul-Chunks mit zwei unterschiedlichen Hashes aus. Das heißt der Angular-Core wurde zweimal vom Prebundler behandelt und beide Versionen wurden in der Angular-App geladen:
| Angeforderte Datei | Typ | Größe |
|---|---|---|
main.js |
script | 104 kB |
@angular_platform-browser.js?v=abc4743f |
script | 50,2 kB |
@angular_core.js?v=abc4743f |
script | 998 kB |
@angular_router.js?v=abc4743f |
script | 261 kB |
| ... | ... | ... |
chunk-GMRBKFW6.js?v=7c52e23b |
script | 89,3 kB |
chunk-KXOBELG4.js?v=7c52e23b |
script | 905 kB |
Zwei unterschiedliche Hashes (abc4743f und 7c52e23b) bedeuten: Angular Core wurde zweimal vorgebündelt und geladen (~998 KB + ~905 KB). Eine Instanz setzt den Injector, die andere findet null – zack, NG0203.
Schritt 3: Den Übeltäter finden
Nachdem klar war, dass wirklich zwei Instanzen von Angular geladen wurden, war die Frage: Warum?
Dabei half ein genauerer Blick in den Sources-Tab der Browser-Dev-Tools.
Dieser zeigte, dass eine Instanz aus C:\Users\rene.poepperl\Documents\Projekt geladen wurde, und die andere aus C:\Users\rene.poepperl.000\Documents\Projekt. Der Übeltäter war also mein Windows-Profilordner.
Was war hier passiert?
Unter Windows entsteht ein Windows-Profilordner mit der Endung .000, wenn Windows bei der Anmeldung das Original-Benutzerprofil nicht laden kann. Dann legt Windows im Hintergrund ein neues Profil an und verknüpft alte Pfade über sogenannte Junctions (Verknüpfungen im Dateisystem, auch Reparse Points genannt).
Eigentlich verweisen diese Junctions letztenendes auf die gleichen Dateien. Aber: Node.js bzw. Vite lösen Pfade an machen Stellen über den realpath() auf und an anderen nicht, und damit entsteht zum Teil eine Inkosistenz bei den Pfadnamen. Vite denkt, es arbeitet mit zwei unterschiedlichen Verzeichnissen und bündelt node_modules doppelt. Herzlichen Glückwunsch!
Die Lösung: Sauberes Workspace-Setup
Der Fix ist simpel, erfordert aber einen konsequenten Umzug:
Verschiebe das Projekt an einen echten, flachen Pfad ohne Reparse-Points (z. B.
C:\dev\DeinProjekt).Wichtig: Nimm den
node_modules-Ordner nicht mit! Sonst schleppst du die kaputten Pfadverweise weiter.Installiere die Abhängigkeiten frisch
Prüfe danach im Dev-Server (Netzwerk-Tab), ob alle Angular-Chunks exakt denselben ?v=...-Hash tragen. Wenn ja, läuft die App wieder stabil.