error.vue — Polishing 404s and 500s

One File Catches Everything

error.vue — Polishing 404s and 500s

A single error.vue at the project root replaces both the 404 and 500 pages, with full access to your branding, layout, and components.

4 min read Level 2/5 #nuxt#errors#404
What you'll learn
  • Differentiate 404 vs 500 by error.statusCode
  • Return users home with clearError
  • Style errors with your full app branding

Nuxt has its own ugly default error page. Replace it by creating error.vue at the project root — same level as app.vue. It receives the error as a prop and catches both 404s and uncaught 500s.

The File

<script setup lang="ts">
const props = defineProps<{
  error: { statusCode: number; message: string }
}>()

const handleHome = () => clearError({ redirect: '/' })
</script>

<template>
  <div class="error">
    <h1 v-if="error.statusCode === 404">Page not found</h1>
    <h1 v-else>Something went wrong</h1>

    <p>{{ error.message }}</p>
    <button @click="handleHome">Back home</button>
  </div>
</template>

Differentiating Status Codes

error.statusCode is the HTTP code — 404 for missing routes, 500 for server errors, anything you throw createError({ statusCode: 403 }) from middleware.

<template>
  <div v-if="error.statusCode === 404">
    <h1>404</h1>
    <p>We couldn't find that page.</p>
  </div>
  <div v-else-if="error.statusCode === 403">
    <h1>Forbidden</h1>
    <p>You don't have access.</p>
  </div>
  <div v-else>
    <h1>Server error</h1>
    <p>Try again in a moment.</p>
  </div>
</template>

clearError

Calling clearError() removes the error from Nuxt’s state — the user sees the normal app again. Pass { redirect: '/' } to also navigate.

// Clear and stay on the current URL
clearError()

// Clear and go home
clearError({ redirect: '/' })

Throwing Errors From Pages

Anywhere in your app, throw createError({ statusCode: 404 }) jumps to error.vue with the right status. Useful in data calls that 404 on the server.

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

Layout Note

error.vue does not use your layouts by default — it’s a stand-alone page. If you want the normal layout, wrap the template in <NuxtLayout>:

<template>
  <NuxtLayout name="default">
    <h1>Oops</h1>
  </NuxtLayout>
</template>
Performance Optimization →