What Causes This Error?
This error occurs when you call addRouteMiddleware() without providing a valid middleware function or with an undefined/null value.
The Problem
// plugins/middleware.ts
export default defineNuxtPlugin(() => {
// ❌ Wrong - undefined middleware
addRouteMiddleware('auth', undefined)
// ❌ Wrong - null middleware
addRouteMiddleware('auth', null)
// ❌ Wrong - empty call
addRouteMiddleware('auth')
})
The Fix
Provide a Valid Middleware Function
// plugins/middleware.ts
export default defineNuxtPlugin(() => {
// ✅ Correct - provide a function
addRouteMiddleware('auth', (to, from) => {
const { user } = useAuth()
if (!user.value && to.meta.requiresAuth) {
return navigateTo('/login')
}
})
})
Common Causes
1. Conditional Middleware Not Checked
// ❌ Wrong - might be undefined
const authMiddleware = config.enableAuth ? createAuthMiddleware() : undefined
addRouteMiddleware('auth', authMiddleware)
// ✅ Correct - only add if defined
if (config.enableAuth) {
addRouteMiddleware('auth', createAuthMiddleware())
}
2. Import Failed Silently
// ❌ Wrong - import might fail
import { myMiddleware } from './middleware' // Might be undefined
addRouteMiddleware('custom', myMiddleware)
// ✅ Correct - verify import
import { myMiddleware } from './middleware'
if (myMiddleware) {
addRouteMiddleware('custom', myMiddleware)
} else {
console.warn('myMiddleware not loaded')
}
3. Async Function Returns Undefined
// ❌ Wrong - async function might return undefined
const getMiddleware = async () => {
if (someCondition) {
return (to, from) => { /* ... */ }
}
// Returns undefined if condition is false!
}
const middleware = await getMiddleware()
addRouteMiddleware('dynamic', middleware)
// ✅ Correct - always return a function
const getMiddleware = async () => {
if (someCondition) {
return (to, from) => { /* ... */ }
}
return () => {} // No-op middleware
}
Proper Usage Patterns
Basic Named Middleware
// plugins/middleware.ts
export default defineNuxtPlugin(() => {
addRouteMiddleware('auth', (to, from) => {
console.log('Auth middleware running')
// Your logic here
})
})
Global Middleware
// plugins/global-middleware.ts
export default defineNuxtPlugin(() => {
addRouteMiddleware('analytics', (to, from) => {
// Track page views
trackPageView(to.fullPath)
}, { global: true }) // Runs on every route
})
Multiple Middleware
// plugins/middleware.ts
export default defineNuxtPlugin(() => {
// Auth middleware
addRouteMiddleware('auth', (to) => {
if (to.meta.requiresAuth && !isAuthenticated()) {
return navigateTo('/login')
}
})
// Admin middleware
addRouteMiddleware('admin', (to) => {
if (!isAdmin()) {
return navigateTo('/forbidden')
}
})
// Logging middleware (global)
addRouteMiddleware('logger', (to, from) => {
console.log(`Navigation: ${from.path} → ${to.path}`)
}, { global: true })
})
Middleware Factory Pattern
// utils/middleware-factory.ts
export function createRoleMiddleware(role: string) {
return (to: RouteLocationNormalized) => {
const user = useUserStore()
if (!user.hasRole(role)) {
return navigateTo('/unauthorized')
}
}
}
// plugins/middleware.ts
export default defineNuxtPlugin(() => {
// ✅ Factory always returns a function
addRouteMiddleware('admin', createRoleMiddleware('admin'))
addRouteMiddleware('editor', createRoleMiddleware('editor'))
})
Conditional Registration
// plugins/middleware.ts
export default defineNuxtPlugin(() => {
const config = useRuntimeConfig()
// ✅ Only register if feature is enabled
if (config.public.enableAuth) {
addRouteMiddleware('auth', (to) => {
// Auth logic
})
}
// ✅ Or use a no-op for disabled features
addRouteMiddleware('auth', config.public.enableAuth
? (to) => { /* actual logic */ }
: () => {} // No-op, but still a valid function
)
})
TypeScript Type Safety
// plugins/middleware.ts
import type { RouteLocationNormalized, NavigationGuardReturn } from 'vue-router'
type MiddlewareFunction = (
to: RouteLocationNormalized,
from: RouteLocationNormalized
) => NavigationGuardReturn | Promise<NavigationGuardReturn>
export default defineNuxtPlugin(() => {
const authMiddleware: MiddlewareFunction = (to) => {
if (to.meta.requiresAuth) {
return navigateTo('/login')
}
}
// TypeScript ensures this is always a function
addRouteMiddleware('auth', authMiddleware)
})
Module Development
// modules/my-module/runtime/plugin.ts
export default defineNuxtPlugin(() => {
// ✅ Always provide a valid function
addRouteMiddleware('my-module-middleware', (to, from) => {
// Module-specific logic
})
})
Debugging
Check if middleware is registered:
// plugins/debug-middleware.ts
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.hook('page:start', () => {
const router = useRouter()
console.log('Registered middleware:', router.getRoutes()
.flatMap(r => r.meta.middleware || []))
})
})
Quick Checklist
- Middleware function is not
undefinedornull - Conditional middleware checks value before calling
addRouteMiddleware - Imported middleware exports exist and are functions
- Async middleware factories always return a function
- Using TypeScript to catch type errors
- Global option is passed correctly:
{ global: true }