Next.js
Error Handling
Build comprehensive error handling for NewsWave using custom error pages, error boundaries, and global error management strategies.
Errors happen. Users break things. APIs fail. Networks timeout. Your NewsWave site needs to handle these gracefully instead of showing cryptic white screens or browser error messages. Next.js provides several layers of error handling. Custom error pages catch route-level failures. Error boundaries trap React component crashes. Global error handlers manage API failures. Think of it like a safety net system — multiple layers catch different types of problems. Unlike plain React where you manually configure error boundaries everywhere, Next.js has built-in conventions. Theerror.js file automatically wraps page components. The not-found.js handles 404s. The global-error.js catches everything else.
Custom Error Pages
Error pages replace the default browser error screen with branded experiences. When a NewsWave article fails to load, users should see a helpful message, not a technical stack trace. Start with the 404 page. This handles "page not found" scenarios — like visiting/articles/fake-slug when that article doesn't exist. The not-found.js file creates custom 404 pages.
Next comes the general error page. This catches runtime errors in your page components — like JavaScript exceptions or failed data fetching. The error.js file creates these error boundaries.
// app/not-found.js - Custom 404 page for NewsWave
export default function NotFound() {
return (
<div className="error-container">
<h1>Article Not Found</h1>
<p>The article you're looking for doesn't exist.</p>
<a href="/">Back to NewsWave Home</a>
</div>
);
}// app/error.js - Main error boundary for NewsWave
'use client'; // Error boundaries must be client components
export default function Error({ error, reset }) {
return (
<div className="error-container">
<h1>Something went wrong</h1>
<p>NewsWave encountered an unexpected error.</p>
<button onClick={reset}>Try Again</button>
</div>
);
}Global Error Handling
Some errors happen outside individual pages — like layout crashes or root-level failures. Theglobal-error.js file catches these application-wide problems.
Global error handlers are the final safety net. When everything else breaks — your layout, your root component, even your main error boundary — this component takes over. It completely replaces your app's HTML structure.
Think of it like an emergency backup generator. Most of the time it sits idle. But when the main power grid fails, it keeps essential systems running. Your global error handler keeps NewsWave functional even when core components crash.
// app/global-error.js - Last resort error handler
'use client';
export default function GlobalError({ error, reset }) {
return (
<html> {/* Must include html and body tags */}
<body>
<div className="global-error">
<h1>NewsWave is temporarily unavailable</h1>
<p>We're experiencing technical difficulties.</p>
<button onClick={reset}>Reload Page</button>
</div>
</body>
</html>
);
}API Error Handling
API routes need their own error handling strategy. When the NewsWave newsletter signup fails or article fetching breaks, you want controlled responses instead of server crashes. API error handling happens in two places. First, inside your API route handlers — catching database failures, validation errors, and external API problems. Second, in your client code — handling network timeouts, 500 errors, and malformed responses. The pattern involves try-catch blocks around risky operations, proper HTTP status codes for different error types, and consistent error response formats. Your frontend code can then handle these predictable error structures.// app/api/articles/route.js - API error handling
export async function GET() {
try {
// Simulate database fetch
const articles = await fetchArticles();
return Response.json({ articles });
} catch (error) {
return Response.json(
{ error: 'Failed to load articles' },
{ status: 500 }
);
}
}// components/ArticleList.js - Client-side API error handling
'use client';
import { useState, useEffect } from 'react';
export default function ArticleList() {
const [articles, setArticles] = useState([]);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetchArticles();
}, []);
const fetchArticles = async () => {
try {
const response = await fetch('/api/articles');
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const data = await response.json();
setArticles(data.articles);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
if (loading) return <div>Loading articles...</div>;
if (error) return <div>Error: {error}</div>;
return (
<div>
{articles.map(article => (
<div key={article.id}>{article.title}</div>
))}
</div>
);
}Error Boundaries for Components
Sometimes you want granular error handling — catching errors in specific components without crashing the entire page. React error boundaries wrap individual components and isolate their failures. Error boundaries work like circuit breakers in electrical systems. When one section overloads, the breaker trips and cuts power to just that area. The rest of your house keeps working normally. Component-level error boundaries protect your page the same way. For NewsWave, you might wrap the comment section in an error boundary. If comments fail to load, the article content still displays perfectly. Users can read the news even when secondary features break.// components/ErrorBoundary.js - Reusable error boundary
'use client';
import { ErrorBoundary } from 'react-error-boundary';
function ErrorFallback({ error, resetErrorBoundary }) {
return (
<div className="error-fallback">
<h3>Something went wrong</h3>
<p>{error.message}</p>
<button onClick={resetErrorBoundary}>Try again</button>
</div>
);
}
export default function SafeComponent({ children }) {
return (
<ErrorBoundary
FallbackComponent={ErrorFallback}
onReset={() => window.location.reload()}
>
{children}
</ErrorBoundary>
);
}// app/articles/[slug]/page.js - Using error boundary
import SafeComponent from '@/components/ErrorBoundary';
import CommentSection from '@/components/CommentSection';
export default function ArticlePage() {
return (
<main>
<article>
<h1>Breaking News Article</h1>
<p>Article content loads reliably...</p>
</article>
<SafeComponent>
<CommentSection /> {/* This might crash */}
</SafeComponent>
</main>
);
}Error Logging and Monitoring
Good error handling doesn't just fix problems — it reports them so you can prevent future issues. Error logging captures crash details, user context, and stack traces for debugging. Production error monitoring is like a security camera system. When something breaks, you want to know what happened, when it occurred, and how to reproduce the problem. Services like Sentry, LogRocket, or DataDog capture this information automatically. Basic error logging starts with console messages and server logs. Advanced monitoring includes user session replays, performance metrics, and automated alerting when error rates spike.// lib/errorLogger.js - Custom error logging
export function logError(error, context = {}) {
// Log to console in development
if (process.env.NODE_ENV === 'development') {
console.error('Error:', error);
console.error('Context:', context);
return;
}
// Send to monitoring service in production
const errorData = {
message: error.message,
stack: error.stack,
timestamp: new Date().toISOString(),
userAgent: navigator.userAgent,
url: window.location.href,
...context
};
// Replace with your monitoring service
fetch('/api/errors', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(errorData)
});
}// app/error.js - Error boundary with logging
'use client';
import { logError } from '@/lib/errorLogger';
import { useEffect } from 'react';
export default function Error({ error, reset }) {
useEffect(() => {
// Log error with context
logError(error, {
component: 'PageErrorBoundary',
userAction: 'pageLoad',
severity: 'high'
});
}, [error]);
return (
<div className="error-container">
<h1>Something went wrong</h1>
<p>NewsWave encountered an error. Our team has been notified.</p>
<button onClick={reset}>Try Again</button>
</div>
);
}Error Recovery Patterns
The best error handling doesn't just show error messages — it helps users recover and continue their tasks. Recovery patterns provide alternative paths when primary features fail. Think about ATM machines. When the card reader breaks, you can still withdraw cash by typing your account number. When the receipt printer fails, you get digital receipts. Good error recovery keeps core functionality working even when individual components break. For NewsWave, implement graceful degradation. If article images fail to load, show placeholder graphics. If the search API times out, fall back to client-side filtering. If comments won't submit, save drafts locally for retry later.// components/ArticleImage.js - Image with fallback
'use client';
import { useState } from 'react';
export default function ArticleImage({ src, alt, title }) {
const [imageError, setImageError] = useState(false);
const [loading, setLoading] = useState(true);
if (imageError) {
return (
<div className="image-fallback">
<div className="placeholder">📰</div>
<p>{title}</p>
</div>
);
}
return (
<div className="article-image">
{loading && <div className="image-loading">Loading...</div>}
<img
src={src}
alt={alt}
onLoad={() => setLoading(false)}
onError={() => {
setLoading(false);
setImageError(true);
}}
style={{ display: loading ? 'none' : 'block' }}
/>
</div>
);
}Quiz
1. The NewsWave team notices that when individual page components crash, users see blank white screens. What Next.js file should they create to handle these errors gracefully?
2. NewsWave wants to ensure that when the comment section fails to load, the main article content remains readable. What's the best approach?
3. When NewsWave fetches articles from /api/articles, the API might return HTTP 500 errors or network timeouts. What's the proper way to handle these in the client component?
Up Next: Next.js Best Practices
Master production-ready patterns, performance optimization, security hardening, and professional development workflows for Next.js applications.