Fix: No Route Middleware Passed to addRouteMiddleware in Nuxt

Error message:
No route middleware passed to `addRouteMiddleware`.
middleware 2025-01-25

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 undefined or null
  • 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 }