Remix Catch Boundaries — Handling Expected Errors
In this tutorial, you will learn about Remix Catch Boundaries. We cover key concepts, practical examples, and best practices to help you master this topic.
Learn Remix catch boundaries: handle expected error responses like 404, 403, and 500, differentiate from unexpected errors, and show user-friendly messages.
In this lesson, you'll implement catch boundaries that handle thrown Response objects separately from unexpected errors, providing appropriate UI for each status code.
What You'll Learn
How catch boundaries work with thrown Responses, handle specific status codes, provide contextual error pages, and use them alongside error boundaries.
Why It Matters
Expected errors (page not found, forbidden, rate limited) need different handling than unexpected bugs. Catch boundaries give you control over how each status code is displayed.
Real-World Use
DodaZIP uses catch boundaries to show "Project not found" with a link to the project list for 404s, and "Upgrade your plan" for 403 errors.
flowchart TD
A[Thrown Response] --> B{Error or Catch?}
B -->|CatchBoundary| C[404/403/500 UI]
B -->|ErrorBoundary| D[Unexpected Error]
style A fill:#121212,color:#fff
Catch Boundary
import { useCatch } from "@remix-run/react";
export function CatchBoundary() {
const caught = useCatch();
switch (caught.status) {
case 404:
return (
<div>
<h1>Page Not Found</h1>
<p>The resource you're looking for doesn't exist.</p>
<a href="/">Go home</a>
</div>
);
case 403:
return (
<div>
<h1>Access Denied</h1>
<p>You don't have permission to view this page.</p>
</div>
);
case 401:
return (
<div>
<h1>Unauthorized</h1>
<p>Please log in to continue.</p>
<a href="/login">Log in</a>
</div>
);
default:
return (
<div>
<h1>Error {caught.status}</h1>
<p>{caught.data}</p>
</div>
);
}
}
Catching in Loaders
Throwing expected errors:
export const loader = async ({ params }) => {
const post = await getPost(params.slug);
if (!post) {
throw new Response("Post not found", { status: 404 });
}
if (post.hidden) {
throw new Response("This post is private", { status: 403 });
}
return json(post);
};
The catch boundary catches these and renders status-specific UI.
Combining Catch and Error Boundaries
Use both for comprehensive error handling:
export function CatchBoundary() {
const caught = useCatch();
// Handle expected errors
}
export function ErrorBoundary() {
const error = useRouteError();
// Handle unexpected errors
}
Remix routes the error to the appropriate boundary automatically.
Nested Catch Boundaries
Child routes can have their own catch boundaries:
// dashboard.analytics.tsx
export function CatchBoundary() {
const caught = useCatch();
// Only handles errors in the analytics route
}
If the child doesn't have a catch boundary, the parent's catches the error.
Common Mistakes
- Using catch boundaries for unexpected errors: Catch boundaries are for thrown Responses. Unexpected errors go to error boundaries.
- Not handling specific status codes: A generic fallback for all status codes defeats the purpose. Provide contextual messages per status.
- Forgetting to export
CatchBoundary: The function must be a named export. Default exports don't work for catch boundaries. - Not updating the root catch boundary: The root's catch boundary is the last resort for all unmatched routes. Customize it for your app.
Practice Questions
What hook accesses caught response data? Answer:
useCatch()from@remix-run/react. It returns the thrown Response withstatus,statusText, anddata.What's the difference between CatchBoundary and ErrorBoundary? Answer: CatchBoundary handles thrown Response objects (expected errors). ErrorBoundary handles unexpected errors (exceptions, bugs).
What happens if no CatchBoundary exists? Answer: The error bubbles to the parent's CatchBoundary or ErrorBoundary. The root boundary handles it as a fallback.
Can a route have both CatchBoundary and ErrorBoundary? Answer: Yes. Export both functions from the same route module. Remix routes errors to the appropriate one.
Challenge
Build a multi-route app where each route handles its own 404 and 403 cases with contextual messages. The parent layout should only catch errors not handled by children.
Mini Project
Create a file management app with catch boundaries: 404 for missing files, 403 for permission-denied files, 413 for files that are too large, and a generic fallback for other errors.
FAQ
What's Next
Learn about Remix Links and Meta for managing SEO tags and link elements per route.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro