React Error Boundaries with Axios: Best Practices
Handling asynchronous API failures in React requires a coordinated strategy because native React Error Boundaries do not catch asynchronous errors out of the box. Combining centralized Axios interceptors with React Error Boundaries creates a resilient architecture that captures network failures, normalizes error responses, and displays appropriate fallback interfaces. This guide outlines best practices for bridging Axios and React Error Boundaries to build a predictable, scalable error-handling pipeline.
1. Bridge the Async Gap with React Error Boundaries
React Error Boundaries only catch errors thrown during rendering, in
lifecycle methods, and in constructors. They do not catch errors inside
asynchronous functions, such as an Axios get or
post request.
To propagate an Axios error to the nearest Error Boundary, re-throw
the error into React's render cycle using a state updater function or a
utility library like react-error-boundary:
import { useState, useCallback } from 'react';
export const useAsyncError = () => {
const [, setError] = useState();
return useCallback((e) => {
setError(() => {
throw e;
});
}, []);
};Using the react-error-boundary package provides the
useErrorBoundary hook, which allows you to call
showBoundary(error) directly inside a .catch()
block or a React Query/SWR error callback.
2. Centralize Error Normalization via Axios Interceptors
Do not handle raw HTTP error payloads inside individual UI components. Use Axios response interceptors to transform diverse backend responses into standardized error objects.
- Categorize by Status Code: Separate network drops (status 0), client errors (4xx), and server crashes (5xx).
- Handle Global Concerns Immediately: Automatically
handle token refreshing or redirection for
401 Unauthorizederrors inside the interceptor rather than throwing them to UI boundaries. - Standardize Shape: Return a consistent interface
containing properties like
message,statusCode,retryable, andoriginalError.
import axios from 'axios';
const apiClient = axios.create({
baseURL: 'https://api.example.com',
});
apiClient.interceptors.response.use(
(response) => response,
(error) => {
if (error.response?.status === 401) {
// Handle authentication refresh or redirection
return Promise.reject(new AuthError('Session expired'));
}
const normalizedError = {
message: error.response?.data?.message || 'An unexpected error occurred.',
status: error.response?.status || 500,
isNetworkError: !error.response,
};
return Promise.reject(normalizedError);
}
);3. Implement Layered Error Boundaries
Do not rely on a single root-level Error Boundary. Structure boundaries hierarchically across three primary tiers:
- Global Boundary: Catches unhandled, catastrophic failures. Displays a generic "Application Error" screen with an option to reload the entire app.
- Route/Page-Level Boundary: Wraps distinct views (e.g., Dashboard, Settings). If a page's initial data fetch fails, navigation elements remain functional while the main view displays a page-specific error.
- Component/Widget-Level Boundary: Wraps isolated, non-critical UI components (e.g., an analytics widget, recommended products list). If the component's Axios request fails, only that widget renders a fallback, preventing the rest of the page from crashing.
4. Provide Reset and Retry Mechanisms
A robust error boundary should allow the user to recover without forcing a full page reload.
- Reset Boundary State: Pass a
resetKeysarray or anonResetcallback to your Error Boundary to clear the error state when route parameters change or when the user clicks a "Try Again" button. - Coordinate with Cache: When resetting the boundary, ensure the invalid or failed cache entry (such as in React Query or RTK Query) is refetched or invalidated.
5. Log Errors for Observability
Use the componentDidCatch lifecycle method or the
onError prop of your boundary to report network and
rendering failures to external monitoring services (such as Sentry or
Datadog). Attach the normalized Axios error details—such as HTTP status
codes and endpoint URLs—while stripping sensitive information like
authentication tokens and personally identifiable information (PII).