What Causes This Warning?
This warning appears when an error occurs in route middleware but there’s no error handler to catch it. Without proper error handling, users may see generic error pages.
The Problem
// middleware/auth.ts
export default defineNuxtRouteMiddleware((to) => {
// ❌ Error thrown without handling
throw new Error('Authentication failed')
// ❌ Or uncaught async error
const user = await getUser() // Might throw
})
The Fix
Use createError
// middleware/auth.ts
export default defineNuxtRouteMiddleware((to) => {
const { user } = useAuth()
if (!user.value) {
// ✅ Use createError for handled errors
throw createError({
statusCode: 401,
statusMessage: 'Unauthorized',
message: 'Please login to access this page'
})
}
})
Add Try-Catch
// middleware/data.ts
export default defineNuxtRouteMiddleware(async (to) => {
try {
const data = await fetchRequiredData(to.params.id)
if (!data) {
throw createError({
statusCode: 404,
message: 'Resource not found'
})
}
} catch (error) {
// ✅ Handle unexpected errors
if (error.statusCode) {
throw error // Re-throw createError errors
}
console.error('Middleware error:', error)
throw createError({
statusCode: 500,
message: 'An error occurred'
})
}
})
Error Page
Create an error page to display errors:
<!-- error.vue -->
<script setup>
const error = useError()
const handleError = () => {
clearError({ redirect: '/' })
}
</script>
<template>
<div class="error-page">
<h1>{{ error.statusCode }}</h1>
<p>{{ error.message }}</p>
<button @click="handleError">Go Home</button>
</div>
</template>
Global Error Handler
// plugins/error-handler.ts
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.hook('vue:error', (error, instance, info) => {
console.error('Vue error:', error)
// Report to error tracking service
})
nuxtApp.hook('app:error', (error) => {
console.error('App error:', error)
// Report to error tracking service
})
})
Middleware Error Patterns
Authentication Check
// middleware/auth.ts
export default defineNuxtRouteMiddleware((to) => {
const { user, isAuthenticated } = useAuth()
if (!isAuthenticated.value) {
// ✅ Redirect instead of error for auth
return navigateTo({
path: '/login',
query: { redirect: to.fullPath }
})
}
})
Permission Check
// middleware/admin.ts
export default defineNuxtRouteMiddleware((to) => {
const { user } = useAuth()
if (!user.value?.isAdmin) {
// ✅ Forbidden error
throw createError({
statusCode: 403,
message: 'Access denied. Admin privileges required.'
})
}
})
Resource Validation
// middleware/validate-id.ts
export default defineNuxtRouteMiddleware((to) => {
const id = to.params.id as string
if (!id || !/^\d+$/.test(id)) {
// ✅ Bad request error
throw createError({
statusCode: 400,
message: 'Invalid ID format'
})
}
})
Async Middleware
// middleware/load-data.ts
export default defineNuxtRouteMiddleware(async (to) => {
try {
const response = await $fetch(`/api/validate/${to.params.slug}`)
if (!response.valid) {
throw createError({
statusCode: 404,
message: 'Page not found'
})
}
} catch (error) {
// Handle fetch errors
if (error.statusCode === 404) {
throw createError({
statusCode: 404,
message: 'Page not found'
})
}
// Log and show generic error
console.error('Validation error:', error)
throw createError({
statusCode: 500,
message: 'Unable to load page'
})
}
})
Error Handling in app.vue
<!-- app.vue -->
<template>
<NuxtLayout>
<NuxtErrorBoundary @error="handleError">
<NuxtPage />
<template #error="{ error, clearError }">
<div class="error-container">
<h2>Something went wrong</h2>
<p>{{ error.message }}</p>
<button @click="clearError">Try again</button>
</div>
</template>
</NuxtErrorBoundary>
</NuxtLayout>
</template>
<script setup>
const handleError = (error) => {
console.error('Caught error:', error)
// Report to error tracking
}
</script>
Testing Error Handlers
// middleware/__tests__/auth.test.ts
import { describe, it, expect } from 'vitest'
describe('auth middleware', () => {
it('throws 401 for unauthenticated users', () => {
// Mock useAuth to return no user
expect(() => {
// Run middleware
}).toThrow()
})
})
Quick Checklist
- Use
createError()for expected errors - Add try-catch for async operations
- Create
error.vuepage for error display - Consider redirect instead of error for auth
- Add global error hooks in plugins
- Use
NuxtErrorBoundaryfor component errors - Log errors for debugging/monitoring