Introduction

Angular's lazy loading splits the application into chunks that are loaded on demand. In production builds, lazy loaded modules may fail to load with errors like:

bash
ERROR Error: Uncaught (in promise): Error: Cannot find module './features/admin/admin.module'
ChunkLoadError: Loading chunk 5 failed.
(error: https://example.com/5.abc123.js)

This typically happens due to route configuration issues, deployment path mismatches, or build optimization problems.

Symptoms

  • Lazy loaded routes work in development (ng serve) but fail in production
  • Browser console shows "Cannot find module" or "ChunkLoadError"
  • Network tab shows 404 for chunk files (e.g., 5.abc123.js)
  • Application works after hard refresh but fails on navigation
  • Error occurs after deploying to a subdirectory or different base href

Common Causes

  • Incorrect loadChildren path syntax in route configuration
  • base-href mismatch between build configuration and deployment path
  • Deployment does not include all generated chunk files
  • Service Worker caches old chunk references after a new deployment
  • Build optimization removes code that is dynamically imported

Step-by-Step Fix

  1. 1.Use the correct loadChildren syntax for your Angular version:
  2. 2.```typescript
  3. 3.// Angular 8+ (recommended)
  4. 4.const routes: Routes = [
  5. 5.{
  6. 6.path: 'admin',
  7. 7.loadChildren: () => import('./features/admin/admin.module')
  8. 8..then(m => m.AdminModule),
  9. 9.},
  10. 10.];

// BAD: string-based syntax (deprecated in Angular 8+) // loadChildren: './features/admin/admin.module#AdminModule' ```

  1. 1.Set the correct base-href in your build command:
  2. 2.```bash
  3. 3.# If deploying to https://example.com/myapp/
  4. 4.ng build --base-href=/myapp/

# Or configure in angular.json ```

  1. 1.Verify all chunk files are deployed. After building, check the dist/ output:
  2. 2.```bash
  3. 3.ls -la dist/myapp/*.js | grep -E "[0-9]+\.[a-f0-9]+\.js"
  4. 4.`
  5. 5.Ensure all chunk files are uploaded to your server/CDN.
  6. 6.Handle chunk load errors with a global error handler:
  7. 7.```typescript
  8. 8.// app.module.ts
  9. 9.import { ErrorHandler } from '@angular/core';
  10. 10.import { Router } from '@angular/router';

export class GlobalErrorHandler implements ErrorHandler { constructor(private router: Router) {}

handleError(error: any) { if (error.message && error.message.includes('Loading chunk')) { // New version deployed, reload the page window.location.reload(); return; } console.error('An error occurred:', error); } }

@NgModule({ providers: [{ provide: ErrorHandler, useClass: GlobalErrorHandler }], }) export class AppModule {} ```

  1. 1.Configure the Service Worker to handle updates properly:
  2. 2.```json
  3. 3.// ngsw-config.json
  4. 4.{
  5. 5."index": "/index.html",
  6. 6."assetGroups": [{
  7. 7."installMode": "prefetch",
  8. 8."updateMode": "prefetch",
  9. 9."resources": {
  10. 10."files": ["/favicon.ico", "/index.html", "/*.css", "/*.js"]
  11. 11.}
  12. 12.}]
  13. 13.}
  14. 14.`

Prevention

  • Always use dynamic import() syntax for lazy loaded modules
  • Include chunk load error handling in every Angular application
  • Test lazy loaded routes in production mode locally: ng build && npx http-server dist/myapp
  • Verify all build artifacts are deployed, not just the main bundle
  • Monitor chunk 404 rates in production to detect deployment issues
  • Use the Angular Service Worker's SwUpdate service to detect and apply updates
  • Add lazy loading route tests to your E2E test suite to verify all routes load correctly