Chapter 7.4โ˜• 15 min read

Error Handling

Every HTTP request can fail. Handle errors gracefully with catchError, user-friendly messages, and a smart global/local strategy.

01Types of HTTP Errors

HTTP errors come in three flavors:

Client errors (4xx) โ€” your fault, bad input:

400 Bad Request      โ€” invalid data format
401 Unauthorized     โ€” not logged in
403 Forbidden        โ€” logged in but no permission
404 Not Found        โ€” resource doesn't exist
422 Validation Error โ€” server rejected the data

Server errors (5xx) โ€” server's fault:

500 Internal Server Error   โ€” server crashed
502 Bad Gateway             โ€” upstream server failed
503 Service Unavailable     โ€” server overloaded

Network errors โ€” the road is closed:

0   โ€” no internet, timeout, CORS issue (no status code at all)

"4xx = tumhari galti, 5xx = server ki galti, network = rasta hi band hai."

02HttpErrorResponse

When an HTTP call fails, Angular wraps the error in an HttpErrorResponse object with detailed properties.

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

this.http.get('/api/biryani').subscribe({
  next: (data) => console.log('Success:', data),
  error: (err: HttpErrorResponse) => {
    console.log('Status:', err.status);         // 404, 500, etc.
    console.log('Message:', err.message);        // "Http failure response..."
    console.log('StatusText:', err.statusText);   // "Not Found", "OK"
    console.log('Error body:', err.error);        // Server's response body
    console.log('URL:', err.url);                 // The URL that failed
  }
});

"HttpErrorResponse = error ka report card โ€” sab details mein."

Key properties:

  • error.status โ€” HTTP status code (number)
  • error.statusText โ€” status text ("Not Found")
  • error.message โ€” human-readable message
  • error.error โ€” server's response body (validation errors, error details)
  • error.url โ€” the URL that failed
  • error.headers โ€” response headers
03catchError Operator

catchError is the RxJS operator that catches errors in the Observable pipeline and lets you return a fallback.

import { catchError, of } from 'rxjs';

this.http.get<Biryani[]>('/api/biryani').pipe(
  catchError((error: HttpErrorResponse) => {
    // Log the error for debugging
    console.error('API Error:', error);

    // Handle specific status codes
    if (error.status === 404) {
      console.log('No biryanis found โ€” showing empty state');
    }
    if (error.status === 500) {
      console.log('Server down โ€” showing retry button');
    }
    if (error.status === 0) {
      console.log('Network error โ€” check internet');
    }

    // Return a safe default value โ€” component won't crash
    return of([]); // Returns Observable that emits empty array
  })
).subscribe(data => {
  this.biryanis = data; // data will be [] if error occurred
});

"catchError = jugaad โ€” error aaya toh koi default value de do."

IMPORTANT: catchError MUST return an Observable. Use of() for a default value or throwError(() => error) to re-throw.

04Global vs Local Error Handling

You can handle errors at two levels โ€” both work together.

Global error handling (interceptor):

// Handles ALL requests โ€” common cases
export const errorInterceptor: HttpInterceptorFn = (req, next) => {
  return next(req).pipe(
    catchError(error => {
      if (error.status === 401) inject(Router).navigate(['/login']);
      if (error.status === 0) showToast('Network error');
      return throwError(() => error); // Re-throw for local handling
    })
  );
};

Local error handling (component):

// Handles SPECIFIC request โ€” unique cases
this.biryaniService.getById(id).pipe(
  catchError(error => {
    if (error.status === 404) {
      this.showNotFoundMessage = true;
    }
    return of(null);
  })
).subscribe(biryani => {
  if (biryani) this.selectedBiryani = biryani;
});

"Global = police, Local = security guard โ€” dono ka kaam alag."

Division of responsibility:

  • Global interceptor: 401 redirect, network error toast, logging
  • Local component: 404 empty state, specific validation error handling
  • Global handles the common cases; local handles the specific ones
05User-Friendly Error Messages

Never show raw error messages to users. Map them to friendly, relatable messages.

// โŒ Raw error โ€” don't show this
"HttpErrorResponse: status 500, message: Internal Server Error"

// โœ… Friendly error โ€” show this
"Server mein kuch problem hai, thodi der baad try karo"
export function getErrorMessage(error: HttpErrorResponse): string {
  switch (error.status) {
    case 400: return 'Galat data bheja hai โ€” form check karo';
    case 401: return 'Pehle login karo bhai';
    case 403: return 'Isko dekhne ki permission nahi hai tumhare paas';
    case 404: return 'Ye biryani exist nahi karti bhai';
    case 422: return 'Server ne data reject kar diya โ€” fields check karo';
    case 500: return 'Server mein kuch problem hai, thodi der baad try karo';
    case 502: return 'Upstream server down hai โ€” kuch der ruko';
    case 503: return 'Server busy hai โ€” thodi der mein aana';
    case 0:   return 'Internet connection check karo โ€” network nahi chal raha';
    default:  return `Kuch to gadbad hai (Error: ${error.status})`;
  }
}

"Error message bhi Hyderabadi hona chahiye โ€” user connect kare."

User-friendly errors improve UX dramatically. A 500 error with a friendly message feels much better than a cryptic technical error.

Key Takeaways

  • โœ… 3 types of errors: 4xx (client), 5xx (server), 0 (network)
  • โœ… HttpErrorResponse has status, statusText, message, error (body), url
  • โœ… catchError catches errors in the pipe โ€” MUST return an Observable (of() or throwError)
  • โœ… Global handling (interceptor) + Local handling (component) work together
  • โœ… Always map raw errors to user-friendly messages โ€” never show HttpErrorResponse to users
Course Search
Search across all chapters & stages
๐Ÿ“–

Search the course

Type any topic โ€” branching, stash, rebase, hooks โ€” and jump straight to that chapter.

merge branchesgit stashundo commitrebase