SDK & Framework Guides

Angular Error Tracking with a Global ErrorHandler

Implement a custom Angular ErrorHandler and the Sentry SDK to catch and report every runtime error, with source maps for readable traces.

Angular's global ErrorHandler is your first line of defense for catching runtime errors. By default, most applications log errors to the console and swallow them. But in production, you need visibility — not just a stack trace in the browser console, but a grouped, searchable issue in a dashboard. This guide shows you how to wire up a custom angular error handler with the Sentry SDK (pointing at LightTrace) so every uncaught exception, HTTP error, and navigation failure becomes an actionable issue.

By the end, you'll capture everything your Angular app throws, with readable stack traces and the context you need to debug fast. The pattern here is the same across any framework — learn how to add error tracking to your app in general, or skip to the Angular specifics below.

Install and initialize the Sentry SDK

Start by adding the Sentry SDK for JavaScript and installing its Angular integration.

npm install @sentry/angular @sentry/tracing

Initialize Sentry as early as possible in your app, ideally before bootstrapping Angular. Open your main.ts and set it up before the platform is created:

// src/main.ts
import * as Sentry from "@sentry/angular";
import { bootstrapApplication } from "@angular/platform-browser";
import { AppComponent } from "./app/app.component";

Sentry.init({
  dsn: "https://<key>@your-lighttrace-host/1",
  environment: "production",
  release: "angular-app@1.0.0",
  tracesSampleRate: 1.0,
  integrations: [
    new Sentry.Replay(),
  ],
});

bootstrapApplication(AppComponent);

The dsn tells the SDK where to send errors. Because LightTrace is Sentry-SDK-compatible, you use the standard Sentry SDK and change only the DSN endpoint — no other changes needed.

Create a custom global ErrorHandler

Angular provides an ErrorHandler service that catches most errors in your application. By default it just logs to the console. Override it to report to LightTrace instead.

// src/app/global-error-handler.ts
import { ErrorHandler, Injectable, Injector } from "@angular/core";
import * as Sentry from "@sentry/angular";

@Injectable({ providedIn: "root" })
export class GlobalErrorHandler implements ErrorHandler {
  constructor(private injector: Injector) {}

  handleError(error: Error | any): void {
    // Capture the error and send it to LightTrace
    Sentry.captureException(error);

    // Still log to console in development
    console.error("Error handled:", error);
  }
}

The Injector lets you access other services if you need them (e.g., to attach request context or user info).

Provide the ErrorHandler to Angular's DI system

Now register your custom handler as the application-wide error handler. In your app configuration (or app.module.ts if using NgModule), provide it:

// src/app/app.config.ts (bootstrapApplication config)
import { ApplicationConfig, ErrorHandler } from "@angular/core";
import { GlobalErrorHandler } from "./global-error-handler";

export const appConfig: ApplicationConfig = {
  providers: [
    { provide: ErrorHandler, useClass: GlobalErrorHandler },
    // ... other providers
  ],
};

Or in app.module.ts for module-based projects:

import { NgModule, ErrorHandler } from "@angular/core";
import { GlobalErrorHandler } from "./global-error-handler";

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

From now on, any uncaught error in a component, service, or event handler automatically routes through your custom handler and gets sent to LightTrace.

Add context so you can debug faster

Raw errors are a starting point. Add user info, breadcrumbs, and tags so you know who hit the error and what they were doing. A stack trace alone won't tell you the path that led to the crash — breadcrumbs do.

// src/app/global-error-handler.ts
import { Router } from "@angular/router";

@Injectable({ providedIn: "root" })
export class GlobalErrorHandler implements ErrorHandler {
  constructor(
    private injector: Injector,
    private router: Router
  ) {}

  handleError(error: Error | any): void {
    // Set the current user
    const user = this.getCurrentUser(); // implement from your auth service
    if (user) {
      Sentry.setUser({ id: user.id, email: user.email });
    }

    // Add breadcrumb for current route
    const route = this.router.routerState.root;
    const url = this.router.url;
    Sentry.addBreadcrumb({
      category: "navigation",
      message: `User at route: ${url}`,
      level: "info",
    });

    Sentry.captureException(error);
    console.error("Error handled:", error);
  }

  private getCurrentUser() {
    // Fetch from your auth service
    return null;
  }
}

Now when an error occurs, the dashboard shows you exactly which user hit it and what page they were on when it happened.

Capture Angular-specific errors

Angular has several error sources beyond the global handler. Wire up a few more to get complete visibility.

Route navigation errors

When route guards reject or navigation fails, handle those explicitly:

// src/app/app.component.ts
import { Router, NavigationError } from "@angular/router";
import * as Sentry from "@sentry/angular";

export class AppComponent implements OnInit {
  constructor(private router: Router) {}

  ngOnInit() {
    this.router.events
      .pipe(filter((event) => event instanceof NavigationError))
      .subscribe((event: NavigationError) => {
        Sentry.captureException(new Error(`Navigation error: ${event.error}`));
      });
  }
}

HTTP error interceptor

HTTP requests that fail should also be tracked. Use an HTTP interceptor to catch failed requests before they become unhandled promise rejections:

// src/app/http-error.interceptor.ts
import { Injectable } from "@angular/core";
import {
  HttpEvent,
  HttpInterceptor,
  HttpHandler,
  HttpRequest,
  HttpErrorResponse,
} from "@angular/common/http";
import { catchError, throwError } from "rxjs";
import * as Sentry from "@sentry/angular";

@Injectable()
export class HttpErrorInterceptor implements HttpInterceptor {
  intercept(
    request: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    return next.handle(request).pipe(
      catchError((error: HttpErrorResponse) => {
        Sentry.captureException(error);
        return throwError(() => error);
      })
    );
  }
}

Provide it in your app config or module:

import { HTTP_INTERCEPTORS } from "@angular/common/http";
import { HttpErrorInterceptor } from "./http-error.interceptor";

providers: [
  {
    provide: HTTP_INTERCEPTORS,
    useClass: HttpErrorInterceptor,
    multi: true,
  },
];

Upload source maps so stack traces are readable

In production, your Angular app is minified, so a raw stack trace points to main-abc123.js:45:12000 — useless. Source maps solve this by mapping minified code back to your original TypeScript.

Enable source map generation in your build. In angular.json:

{
  "projects": {
    "my-app": {
      "architect": {
        "build": {
          "options": {
            "sourceMap": true,
            "optimization": true
          }
        }
      }
    }
  }
}

Then automate source map uploads in your CI pipeline so LightTrace can de-minify traces. Our source maps guide covers the full setup.

Even with source maps enabled locally, production builds often skip them for bundle size. Always upload source maps after deploy so LightTrace has them available when an error occurs.

Common Angular errors to watch

A few Angular-specific errors show up constantly. With your error handler in place, these stop being hard-to-reproduce mysteries and become grouped issues with stack traces and user context.

  • Cannot match any routes — a route guard or resolver rejected navigation.
  • Cannot read properties of undefined — the most common runtime error across all JavaScript frameworks; read how to fix it.
  • Unhandled promise rejection — an async operation (HTTP, animation, subscription) rejected without a catch handler.

Each appears in your LightTrace dashboard with the exact file and line that failed, thanks to source maps.

Test your setup

Before deploying, trigger a test error to make sure it reaches LightTrace. Add a button to your app:

testError() {
  throw new Error("Test error from Angular");
}

Click it, and within seconds the error should appear in your LightTrace dashboard grouped as a new issue.

Start tracking errors in minutes

Set up a global ErrorHandler in your Angular app and start capturing production errors today — get readable stack traces and grouped issues for free.

That's the full setup: Sentry SDK initialized, custom ErrorHandler catching errors, breadcrumbs and user context attached, route and HTTP errors wired up, and source maps making traces readable. Your next production bug becomes a line in your dashboard instead of a user complaint. Deploy with confidence.

Fix your next production error faster

Point any Sentry SDK at LightTrace — free up to 5,000 events/month.