Custom Error Pages

error.vue at the Project Root

Custom Error Pages

A root-level error.vue handles 404 and 500 responses. Use clearError to recover and return the user to safe ground.

4 min read Level 2/5 #nuxt#errors
What you'll learn
  • Create error.vue at the project root
  • Read the error prop and branch by status code
  • Call clearError to recover from a runtime error

When a route does not match, validation fails, or a runtime error escapes a page, Nuxt looks for a project-level error.vue. It is your single fallback UI for the whole app.

Anatomy

error.vue lives next to app.vue (not inside pages/). It receives an error prop with at least statusCode, statusMessage, and message.

<!-- error.vue -->
<script setup lang="ts">
const props = defineProps<{
  error: {
    statusCode: number
    statusMessage?: string
    message: string
  }
}>()

function goHome() {
  clearError({ redirect: '/' })
}
</script>

<template>
  <section class="error">
    <h1>{{ props.error.statusCode }}</h1>
    <p>{{ props.error.statusMessage ?? props.error.message }}</p>
    <button @click="goHome">Go home</button>
  </section>
</template>

clearError resets the error state. With a redirect option it also navigates somewhere safe.

Branching by Status

Treat 404 and 500 differently — a missing post needs a friendlier nudge than a backend crash.

<template>
  <template v-if="error.statusCode === 404">
    <h1>Page not found</h1>
    <p>The link may be old or mistyped.</p>
  </template>
  <template v-else>
    <h1>Something broke</h1>
    <p>Our team has been notified.</p>
  </template>
</template>

Throwing Errors From Pages

Inside a page or composable, use createError to surface a status that triggers error.vue:

const { data: post } = await useFetch(`/api/posts/${slug}`)
if (!post.value) {
  throw createError({ statusCode: 404, statusMessage: 'Post not found' })
}

On the server, this also sets the HTTP status code — search engines see a proper 404. On the client, Nuxt swaps the page for error.vue instantly.

This wraps up routing. Next we move into data fetching — bringing your app to life with real content.

Data Fetching →