← Back to Articles         
How do you handle API errors in Angular?

How do you handle API errors in Angular?

Published on 02 Oct 2026     8 min read Angular
Error Handling

How Do You Handle API Errors in Angular?

1. What is API Error Handling in Angular?

API error handling means detecting and managing errors that occur when an Angular application communicates with a backend API.

For example, your Angular application may call an ASP.NET Core Web API:

Angular
   |
   | HTTP Request
   v
ASP.NET Core Web API
   |
   | HTTP Response
   v
Angular

The API may return errors such as:

Status Meaning
400 Bad Request / validation error
401 Unauthorized
403 Forbidden
404 Resource not found
409 Conflict
500 Internal Server Error
503 Service unavailable
0 Often network/CORS/connectivity failure from Angular's perspective

Angular's HttpClient returns an Observable, so API errors are commonly handled using RxJS catchError().


2. Full Simple Sample Program

Let's use a simple Angular application that calls:

GET https://localhost:7001/api/products

We will handle errors inside a reusable ProductService.

product.ts

export interface Product {
  id: number;
  name: string;
  price: number;
}

product.service.ts

import { inject, Injectable } from '@angular/core';
import {
  HttpClient,
  HttpErrorResponse
} from '@angular/common/http';

import {
  catchError,
  Observable,
  throwError
} from 'rxjs';

import { Product } from './product';

@Injectable({
  providedIn: 'root'
})
export class ProductService {

  private http = inject(HttpClient);

  private apiUrl = 'https://localhost:7001/api/products';

  getProducts(): Observable<Product[]> {

    return this.http.get<Product[]>(this.apiUrl)
      .pipe(
        catchError(error => this.handleError(error))
      );
  }

  private handleError(error: HttpErrorResponse) {

    let message = 'An unexpected error occurred.';

    if (error.status === 0) {
      message = 'Unable to connect to the server.';
    }
    else if (error.status === 400) {
      message = 'Invalid request.';
    }
    else if (error.status === 401) {
      message = 'You are not authorized.';
    }
    else if (error.status === 403) {
      message = 'You do not have permission.';
    }
    else if (error.status === 404) {
      message = 'Requested resource was not found.';
    }
    else if (error.status >= 500) {
      message = 'Server error. Please try again later.';
    }

    console.error('API Error:', error);

    return throwError(() => new Error(message));
  }
}

products.ts

import { Component, inject } from '@angular/core';
import { ProductService } from './product.service';
import { Product } from './product';

@Component({
  selector: 'app-products',
  standalone: true,
  templateUrl: './products.html'
})
export class Products {

  private productService = inject(ProductService);

  products: Product[] = [];

  errorMessage = '';

  loadProducts() {

    this.errorMessage = '';

    this.productService.getProducts()
      .subscribe({
        next: (data) => {
          this.products = data;
        },

        error: (error) => {
          this.errorMessage = error.message;
        }
      });
  }
}

products.html

<h2>Products</h2>

<button (click)="loadProducts()">
  Load Products
</button>

@if (errorMessage) {
  <p>
    {{ errorMessage }}
  </p>
}

@for (product of products; track product.id) {
  <div>
    {{ product.name }} - {{ product.price }}
  </div>
}

app.config.ts

For a standalone Angular application, configure HttpClient:

import {
  ApplicationConfig
} from '@angular/core';

import {
  provideHttpClient
} from '@angular/common/http';

export const appConfig: ApplicationConfig = {

  providers: [
    provideHttpClient()
  ]

};

3. Explanation

The important part is:

return this.http.get<Product[]>(this.apiUrl)
  .pipe(
    catchError(error => this.handleError(error))
  );

The flow is:

Component
   |
   | getProducts()
   v
ProductService
   |
   | HttpClient GET
   v
ASP.NET Core API
   |
   +------------------------+
   |                        |
 Success                  Error
   |                        |
   v                        v
next()                  catchError()
   |                        |
   v                        v
Display products       handleError()
                            |
                            v
                       throwError()
                            |
                            v
                    Component error()

HttpErrorResponse

Angular represents HTTP failures using HttpErrorResponse.

private handleError(error: HttpErrorResponse)

It contains useful information such as:

error.status
error.statusText
error.message
error.error
error.url

For example:

if (error.status === 404) {
  message = 'Requested resource was not found.';
}

4. What does catchError() do?

catchError() is an RxJS operator that intercepts an error emitted by an Observable.

this.http.get<Product[]>(url)
  .pipe(
    catchError(error => ...)
  );

Without catchError(), the error can still reach the subscriber:

.subscribe({
  next: data => {},
  error: error => {}
});

But catchError() lets you process or transform the error before passing it to the component.


5. What does throwError() do?

After processing the API error, we can return an error Observable:

return throwError(() => new Error(message));

For example, the API returns:

HTTP 404

The service converts it into:

Requested resource was not found.

Then the component receives it:

error: (error) => {
  this.errorMessage = error.message;
}

6. Service-Level vs Component-Level Error Handling

There are generally several places where errors can be handled.

Component

this.productService.getProducts()
  .subscribe({
    next: data => {
      this.products = data;
    },
    error: error => {
      this.errorMessage = error.message;
    }
  });

Useful for UI-specific behavior.

For example:

Show "Products could not be loaded"

Service

.pipe(
  catchError(error => this.handleError(error))
)

Useful when error handling is specific to that service or API operation.

HTTP Interceptor

For larger applications, common/global errors are usually handled using an HTTP interceptor.

For example:

401 → redirect to login
403 → show forbidden message
500 → show generic server error
Logging → log all HTTP errors

Architecture:

Component
    |
    v
ProductService
    |
    v
Error Interceptor
    |
    v
ASP.NET Core Web API

7. Global Error Handling Using an Interceptor

In a real Angular application, you often don't want to repeat:

catchError(...)

in every service.

You can create an interceptor.

error.interceptor.ts

import { HttpErrorResponse, HttpInterceptorFn } 
  from '@angular/common/http';

import { catchError, throwError } from 'rxjs';

export const errorInterceptor: HttpInterceptorFn =
  (req, next) => {

    return next(req).pipe(

      catchError((error: HttpErrorResponse) => {

        if (error.status === 401) {

          console.error('Unauthorized');

        }
        else if (error.status === 403) {

          console.error('Forbidden');

        }
        else if (error.status === 404) {

          console.error('Resource not found');

        }
        else if (error.status >= 500) {

          console.error('Server error');

        }

        return throwError(() => error);
      })

    );
  };

Register it in app.config.ts

import {
  ApplicationConfig
} from '@angular/core';

import {
  provideHttpClient,
  withInterceptors
} from '@angular/common/http';

import {
  errorInterceptor
} from './error.interceptor';

export const appConfig: ApplicationConfig = {

  providers: [

    provideHttpClient(
      withInterceptors([
        errorInterceptor
      ])
    )

  ]

};

Now the interceptor can inspect errors from requests passing through that HttpClient configuration.


8. Which Approach Should You Use?

A practical Angular application commonly combines them:

              API Error
                  |
                  v
        Error Interceptor
                  |
        Common/global handling
                  |
                  v
              Service
                  |
        API-specific handling
                  |
                  v
             Component
                  |
          UI-specific handling

For example:

Interceptor

401 → authentication handling
403 → authorization handling
500 → global notification/logging

Service

404 → Product not found
409 → Product already exists

Component

Display the appropriate message

9. Important: Don't Expose Raw Server Errors

Avoid directly displaying:

error.message

or:

error.error

to the user without considering what the backend returns.

A backend might expose technical information that should not appear in the UI.

Prefer converting backend errors into user-friendly messages:

if (error.status >= 500) {
  message = 'Something went wrong. Please try again later.';
}

Technical details can instead be logged appropriately.


Key Points

  • Angular uses HttpClient to communicate with APIs.
  • HttpClient returns Observables.
  • HTTP failures are represented by HttpErrorResponse.
  • Use RxJS catchError() to intercept Observable errors.
  • Use throwError() when you want to propagate an error.
  • Handle UI-specific errors in the component.
  • Handle API/service-specific errors in the service when appropriate.
  • Use an HTTP interceptor for common/global HTTP error handling.
  • 401 means unauthenticated/unauthorized authentication-wise; 403 means authenticated but not permitted in the typical API authorization model.
  • 404 means the requested resource was not found.
  • 5xx indicates a server-side failure.
  • status === 0 commonly means Angular did not receive a normal HTTP response; causes can include network failure, CORS blocking, or the server being unreachable.
  • Don't expose sensitive backend exception details to users.
  • In modern standalone Angular, functional interceptors with withInterceptors() are a clean approach.

Interview Questions and Answers

1. How do you handle API errors in Angular?

Angular API errors can be handled using HttpErrorResponse, RxJS catchError(), and the error callback of subscribe(). For application-wide HTTP error handling, an HTTP interceptor is commonly used.


2. What is HttpErrorResponse?

HttpErrorResponse represents an error returned or encountered during an Angular HTTP request.

catchError((error: HttpErrorResponse) => {
  console.log(error.status);
  return throwError(() => error);
})

3. What is catchError()?

catchError() is an RxJS operator used to intercept and handle errors emitted by an Observable.

.pipe(
  catchError(error => {
    return throwError(() => error);
  })
)

4. What is throwError()?

throwError() creates an Observable that emits an error.

return throwError(
  () => new Error('API failed')
);

It is commonly used to propagate an error after processing it.


5. Where should API errors be handled?

It depends on the scope:

Component   → UI-specific handling
Service     → API/business-specific handling
Interceptor → Global/common HTTP handling

6. Why use an HTTP interceptor for error handling?

An interceptor centralizes common error handling so the same logic does not have to be duplicated across every service.

For example:

401 → authentication handling
403 → authorization handling
500 → generic server-error handling

7. How do you handle a 401 error?

A global error interceptor can detect it:

if (error.status === 401) {
  // Clear invalid authentication state
  // Redirect to login if appropriate
}

The backend must still enforce authentication and authorization; Angular-side handling is primarily for user experience.


8. What is the difference between 401 and 403?

401 → Authentication is missing/invalid
403 → Request is understood, but access is forbidden

A common Angular UX is:

401 → Login
403 → Unauthorized/Access Denied page

9. What does status === 0 mean in Angular?

It means Angular did not receive a normal HTTP response. Common causes include:

API unavailable
Network failure
CORS blocking
Connection failure

You need to inspect the browser's Network tab and console to determine the actual cause.


Interview Quick Answer

How do you handle API errors in Angular?

Angular API errors are typically handled using HttpErrorResponse and RxJS catchError(). For application-wide handling, I use an HTTP interceptor for common cases such as 401, 403, and 500, while service/component-level handling is used for operation-specific errors and user-facing messages.

← Back to Articles