vuejs/vue-router · error · Error
[vue-router]: Missing current instance. ${method}() must be
Error message
[vue-router]: Missing current instance. ${method}() must be called inside <script setup> or setup(). What it means
vue-router's composition APIs (useRouter, useRoute, onBeforeRouteUpdate, onBeforeRouteLeave, useLink) rely on Vue's getCurrentInstance() to find the component instance they belong to. throwNoCurrentInstance throws when none exists, i.e. the API was called outside of a component's setup()/<script setup> context. This is a hard throw (not a warning) so the mistake is caught early in development.
Source
Thrown at src/composables/utils.js:7
import { getCurrentInstance } from 'vue'
// dev only warn if no current instance
export function throwNoCurrentInstance (method) {
if (!getCurrentInstance()) {
throw new Error(
`[vue-router]: Missing current instance. ${method}() must be called inside <script setup> or setup().`
)
}
}
View on GitHub (pinned to 680ccc68c5)
Solutions
- Move the call into the synchronous body of setup() or <script setup>.
- If you need the router outside setup, pass the router instance in explicitly or use the router exported from your router setup module (createRouter result).
- Inside async callbacks, capture const router = useRouter() first in setup, then use the captured variable in the callback.
Example fix
// before (utils.js, throws)
export function goHome () {
const router = useRouter()
router.push('/')
}
// after (component)
import { useRouter } from 'vue-router'
export default {
setup () {
const router = useRouter()
const goHome = () => router.push('/')
return { goHome }
}
} Defensive patterns
Strategy: validation
Validate before calling
import { getCurrentInstance } from 'vue'
function canUseRouterApis () {
return Boolean(getCurrentInstance())
}
// call synchronously inside setup(); if false, use an explicitly passed router instead Type guard
function hasRouterInstance () {
return typeof getCurrentInstance === 'function' && !!getCurrentInstance()
} Prevention
- Only call useRouter/useRoute/onBeforeRoute*/useLink in the synchronous top-level body of setup() or <script setup>.
- Capture the router/route objects into local consts in setup before using them in async callbacks or event handlers.
- For non-component modules, import the router instance created by createRouter instead of composition APIs.
- Lint with eslint-plugin-vue rules / code review to catch router API calls inside setTimeout/Promise callbacks.
When it happens
Trigger: Calling useRouter()/useRoute()/onBeforeRoute*/useLink() at module top level, inside setTimeout/setInterval/Promise.then callbacks, in event handlers after setup finished, in plain .js utility files, or in non-component contexts like store actions.
Common situations: Extracting a navigation helper into a standalone composable file and calling useRouter() there directly; calling useRoute() inside a debounce/timeout; upgrading from Vue Router 3 where this.$router was accessible anywhere via the Vue prototype.
Related errors
- In Vue Router 4, the v-slot API will by default wrap its con
- [vue-router] ${message}
- uncaught error during route navigation:
- Failed to resolve async component ${key}: ${reason}
- <router-link> with to="${this.to}" is trying to use a scoped
AI-assisted analysis of vuejs/vue-router@680ccc68c5 (2026-09-02).
Data as JSON: /api/errors/7d07bc11db2b45c4.
Report an issue: GitHub.