Error Handling
Every HTTP request can fail. Handle errors gracefully with catchError, user-friendly messages, and a smart global/local strategy.
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."
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 messageerror.errorโ server's response body (validation errors, error details)error.urlโ the URL that failederror.headersโ response headers
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.
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
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
Want to track your progress?
Log in to save your place and pick up where you left off.
Progress track karna chahte ho?
Login karo apni progress save karne ke liye aur jahan chhoda tha wahan se shuru karo.
Login