How Nuxt automatically forwards runtime errors, and how clearError() enables recovery
Nuxt automatically catches unhandled runtime errors and renders the error.vue file in the project root in their place. clearError() lets you deliberately leave the error state again, while the display can be tailored individually to 404 or 500 situations depending on the status code.
Table of Contents
- 1. How Nuxt Automatically Forwards Runtime Errors
- 2. The Structure of error.vue
- 3. clearError() for Recovery Actions
- 4. Different Display Depending on the Status Code
- 5. Difference Between Server-Side and Client-Side Errors
- 6. Throwing Custom Errors Deliberately
- 7. Layout and Styling of the Error Page
- 8. showError() for Programmatically Triggering the Error State
- 9. Conclusion: A Well-Designed Error Page Belongs to the Application
- 10. Summary
- 11. FAQ
1. How Nuxt Automatically Forwards Runtime Errors
When a page, a middleware, or a server handler in Nuxt throws an unhandled error, Nuxt catches it automatically and switches into a global error state. Instead of the normal page, the error.vue file in the project root then gets rendered, serving as a kind of global fallback for every error situation across the entire project.
This mechanism applies both to errors that occur during server-side rendering, such as a failed database call inside useAsyncData, and to errors that only surface later in the browser, such as a failed API call after a user interaction. In both cases, error.vue gets access to the details of the error through a dedicated prop.
2. The Structure of error.vue
error.vue lives directly in the project root, at the same level as app.vue, rather than inside the pages directory, since it's a special file reserved by Nuxt. The component receives the error that occurred as a prop named error, which includes fields such as statusCode, statusMessage, and message.
Since error.vue renders outside the normal layout system, the component has to bring its own complete HTML skeleton, including its own header and footer if those should also be visible on the error page. An existing default.vue layout does not get applied to the error page automatically.
3. clearError() for Recovery Actions
The global error state in Nuxt persists until it's explicitly left again. For that, Nuxt provides the clearError() function, which resets the error state and optionally redirects to another route. A typical use case is a button on the error page labeled Back to Home that calls clearError() with a target route when clicked.
Without calling clearError(), the application would remain stuck in the error state indefinitely, even if the user tries to navigate to a working page through the browser. This explicit reset is therefore a necessary part of any well-designed error page and should never be forgotten.
<!-- error.vue -->
<template>
<div class="error-page">
<h1>{{ error.statusCode }}</h1>
<p v-if="error.statusCode === 404">
Sorry, this page could not be found.
</p>
<p v-else>
Something went wrong on our end.
</p>
<button @click="handleRetry">Back to Home</button>
</div>
</template>
<script setup lang="ts">
import type { NuxtError } from '#app';
const props = defineProps<{ error: NuxtError }>();
function handleRetry() {
clearError({ redirect: '/' });
}
</script>
4. Different Display Depending on the Status Code
Since error.statusCode is available as a reactive value inside error.vue, the display can be tailored to the specific status code without extra effort. A 404 status generally warrants a friendly, non-alarming text with suggestions for further navigation, while a 500 status deserves more of an apology, possibly along with a note that the issue has been reported automatically to the development team.
In practice, a small lookup table or a switch statement inside error.vue is worthwhile, providing a fitting heading, text, and recommended actions for the most common status codes like 404, 403, and 500, rather than showing the same generic text for every error.
5. Difference Between Server-Side and Client-Side Errors
A server-side error, such as a failed database call during the initial render, causes the browser to receive the rendered error.vue page directly along with the corresponding HTTP status code. In this case, search engines and other crawlers correctly see a 404 or 500 status code in the HTTP response, which matters for SEO purposes.
A client-side error that only occurs after hydration in the browser, for instance triggered by a failed user action, does not change the page's original HTTP status code, since that response has long since completed. Instead, the application switches into the error state on the client and displays error.vue as an overlay on top of the existing page, without a new server call carrying a new status code.
6. Throwing Custom Errors Deliberately
The createError() function lets you deliberately create custom errors with a chosen status code and message inside pages, middleware, or server handlers. This is especially useful when a resource technically loaded successfully but doesn't exist in a meaningful sense, such as a product with an invalid ID that should be treated as a 404 on the server.
When the optional fatal: true parameter is passed to createError(), Nuxt immediately forces a switch into the global error state and renders error.vue, rather than treating the error as a local state that a component could handle on its own. Without this flag, an error can, in certain contexts, also be caught locally without replacing the entire page.
7. Layout and Styling of the Error Page
Since error.vue doesn't automatically receive a layout from the layouts directory, it's advisable to extract shared building blocks like the header and footer into their own reusable components and include them both in the normal layout and directly inside error.vue. That keeps the error page's appearance consistent with the rest of the application without duplicating markup.
For Tailwind-based projects, styling inside error.vue works exactly like in any other component, as long as the global styles are wired up correctly. A common mistake is overlooking error.vue while testing and only discovering in production that it visually doesn't match the rest of the application.
8. showError() for Programmatically Triggering the Error State
Besides createError(), which is typically used together with a throw, Nuxt offers showError() as an alternative for triggering the global error state directly, without an exception. This is useful, for example, in a global error handler that reacts to an unhandled promise rejection event and only then decides whether the entire application should switch into the error state.
While createError() primarily produces an error object that then gets thrown, showError() directly performs the switch into the global state and renders error.vue. In practice, both functions are often used together: createError() to produce a consistent error object, and showError() to deliberately activate the error state outside the regular rendering cycle.
9. Conclusion: A Well-Designed Error Page Belongs to the Application
A well-designed error.vue is more than a technical necessity, it's an integral part of the user experience, especially in moments when something has gone wrong. Instead of the generic default Nuxt error page, every production project should provide its own, on-brand error page with clear recommended actions and working recovery paths.
Anyone who consistently uses clearError(), tailors the display to the status code, and understands the difference between server-side and client-side errors builds an error page that doesn't leave users stranded, but instead shows them a clear way back to a working page.
| Aspect | Server-Side Error | Client-Side Error |
|---|---|---|
| Timing | During SSR / initial request | After hydration, in the browser |
| HTTP status code | Set correctly in the response | Original response already completed |
| SEO relevance | High, crawlers see the real status code | Low, no new HTTP response |
| Typical cause | Failed useAsyncData fetch | Failed user action, API call |
| Reset | clearError() with optional redirect | clearError() with optional redirect |
Mironsoft
Vue architecture, Composition API, and Nuxt performance
Vue applications that don't get more complicated with every feature?
We review existing Vue and Nuxt projects for unstructured composables, unnecessary reactivity, and bloated bundles, then build an architecture that absorbs new features without making the codebase harder to follow.
Architecture Review
Checking composables, state management, and component structure for maintainability.
Performance Audit
Systematically optimizing reactivity overhead, bundle size, and Nuxt rendering strategy.
Nuxt Integration
Building robust, type-safe SSR/SSG setup and API integration.
10. Summary
Nuxt error.vue: The Essentials at a Glance
File
error.vue in the project root, outside the pages directory
Recovery
clearError() deliberately resets the global error state
Status code access
error.statusCode as a reactive prop for tailored display
Custom errors
createError() with fatal: true forces the global error state