call composable in plugin

if i have a composable and a function from it is to fetch data, if onresponse error then will navigateto login page. and this function i call insie plugin will the navigate work?
8 Replies
kapa.ai
kapa.ai2mo ago
Hi @Zhaolin Lau. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- If you call a composable function that fetches data and handles errors (such as navigating to the login page on a 401 error) inside a Nuxt plugin, the navigation with navigateTo('/login') can work, but there are important caveats: - Composables in Plugins: You can use composables inside plugins, but you must be aware that plugins are initialized before the Vue component lifecycle. If your composable depends on the Vue instance or lifecycle hooks, it may not work as expected in a plugin context. Composables that only use Nuxt app context (like useNuxtApp) are generally safe, but those relying on component context are not.
See: Using Composables in Plugins (Nuxt 3)
See: Using Composables in Plugins (Nuxt 4) - Navigation in Plugins: If you trigger navigateTo inside a plugin (for example, in an API error handler), it will work as long as you are in the correct context. The recommended way to ensure this is to use nuxtApp.runWithContext(() => navigateTo('/login')) inside your plugin's error handler. This ensures the navigation is performed in the right Nuxt context, even during SSR or plugin initialization.
See: Custom useFetch Recipe (Nuxt 3)
See: Custom useFetch Recipe (Nuxt 4) Example from the docs:
export default defineNuxtPlugin((nuxtApp) => {
const api = $fetch.create({
// ...
async onResponseError({ response }) {
if (response.status === 401) {
await nuxtApp.runWithContext(() => navigateTo('/login'))
}
},
})
return {
provide: { api },
}
})
export default defineNuxtPlugin((nuxtApp) => {
const api = $fetch.create({
// ...
async onResponseError({ response }) {
if (response.status === 401) {
await nuxtApp.runWithContext(() => navigateTo('/login'))
}
},
})
return {
provide: { api },
}
})
Custom useFetch Recipe (Nuxt 4) Summary:
- Yes, you can call a composable in a plugin and perform navigation on error, but you must use nuxtApp.runWithContext to ensure navigateTo works correctly in the plugin context. - If your composable depends on the Vue component instance, it may not work as expected in a plugin. If you need more advanced error handling or want to ensure this works both client- and server-side, always test your implementation in both environments. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2mo ago
<@520675622830342144> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Zhaolin Lau
Zhaolin LauOP2mo ago
@kapa.ai this is the function from composable: const fetchInitialData = async () => { await $api('/admin/api/adminInitialData', { async onRequestError() { useCookie('token').value = null useCookie('domain').value = null await navigateTo('/login') }, async onResponse({ response }) { if (response.ok) { const mainStore = useMainStore() const authStore = useAuthStore() if (response._data.initialData) { mainStore.setInitialData(response._data.initialData) } if (response._data.settingData) { mainStore.setSettingData(response._data.settingData) } if (response._data.profileData) { mainStore.setProfileData(response._data.profileData) authStore.setRolePermissions( response._data.profileData.role, response._data.profileData.permissions, ) authStore.setMerchantPermissions( response._data.profileData.merchantPermissions, ) authStore.setWorkspacePermissions( response._data.profileData.workspacePermissions, ) } } else { useCookie('token').value = null useCookie('domain').value = null await navigateTo('/login') } }, async onResponseError() { useCookie('token').value = null useCookie('domain').value = null await navigateTo('/login') }, }) } and i direct call in plugin.
kapa.ai
kapa.ai2mo ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- If you call your fetchInitialData composable function directly inside a Nuxt plugin, the navigation with navigateTo('/login') may not always work as expected unless you ensure the correct Nuxt context is available. According to the official Nuxt documentation, when you perform navigation (such as with navigateTo) inside a plugin—especially after an async operation or inside a callback like onResponseError—you should wrap the navigation call with nuxtApp.runWithContext. This ensures that the Nuxt context is properly restored, which is necessary for navigation to work reliably in plugin or middleware scenarios, particularly during SSR or outside of component setup functions. How to fix your code: You should update your composable or plugin usage like this:
export default defineNuxtPlugin((nuxtApp) => {
// ...
await nuxtApp.runWithContext(() => fetchInitialData())
})
export default defineNuxtPlugin((nuxtApp) => {
// ...
await nuxtApp.runWithContext(() => fetchInitialData())
})
And inside your composable, for every place you call navigateTo, you should also ensure it's wrapped with nuxtApp.runWithContext if not already in the right context. Alternatively, you can pass nuxtApp to your composable or use useNuxtApp() inside it:
const fetchInitialData = async () => {
const nuxtApp = useNuxtApp()
await $api('/admin/api/adminInitialData', {
async onRequestError() {
useCookie('token').value = null
useCookie('domain').value = null

await nuxtApp.runWithContext(() => navigateTo('/login'))
},
// ... same for onResponse and onResponseError
})
}
const fetchInitialData = async () => {
const nuxtApp = useNuxtApp()
await $api('/admin/api/adminInitialData', {
async onRequestError() {
useCookie('token').value = null
useCookie('domain').value = null

await nuxtApp.runWithContext(() => navigateTo('/login'))
},
// ... same for onResponse and onResponseError
})
}
Summary:
- If you call a composable that uses navigateTo inside a plugin, you must use nuxtApp.runWithContext to ensure navigation works correctly in all contexts, especially after async operations or in error handlers. - This is a documented pattern in the Nuxt docs for custom fetch plugins and error handling in plugins Custom useFetch Recipe (Nuxt 4) and runWithContext explanation. If you do not use runWithContext, you may encounter errors like "Nuxt instance unavailable" and navigation may silently fail, especially during SSR or outside of component setup functions. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2mo ago
<@520675622830342144> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Zhaolin Lau
Zhaolin LauOP2mo ago
@kapa.ai my current issue is it didn't redirect to login, it show full page 401
kapa.ai
kapa.ai2mo ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- If your Nuxt app is showing a full-page 401 error instead of redirecting to the login page, it means the error is being handled by Nuxt's global error handler, which renders the error page, rather than your navigation logic. Why this happens: - If you throw an error or let an unhandled error occur during SSR or in a plugin, Nuxt will render the error page (~/error.vue if present, or the default error page) instead of performing a redirect. - The navigateTo('/login') function is intended for client-side navigation. On the server side (SSR), you need to ensure that a redirect response is sent before the error is handled globally. How to handle 401 and redirect to login: 1. In a Nuxt plugin or composable, use nuxtApp.runWithContext to wrap your navigation logic.
This ensures the Nuxt context is available for navigation, especially after async operations or in error handlers. 2. For SSR, use navigateTo for redirection, not by throwing an error.
If you throw an error, Nuxt will show the error page. If you return navigateTo('/login') or await it, Nuxt will perform a redirect. Example from the official docs:
export default defineNuxtPlugin((nuxtApp) => {
const api = $fetch.create({
// ...
async onResponseError({ response }) {
if (response.status === 401) {
await nuxtApp.runWithContext(() => navigateTo('/login'))
}
},
})

return {
provide: { api },
}
})
export default defineNuxtPlugin((nuxtApp) => {
const api = $fetch.create({
// ...
async onResponseError({ response }) {
if (response.status === 401) {
await nuxtApp.runWithContext(() => navigateTo('/login'))
}
},
})

return {
provide: { api },
}
})
Custom useFetch Recipe (Nuxt 4) Key points: - Do not throw an error for 401 if you want to redirect; use navigateTo instead. - Make sure you are not returning or throwing an error after calling navigateTo, as this will trigger the error page. - If you are using useAsyncData or useFetch, handle the error and call navigateTo in the error handler, not by throwing. If you still see the error page:
- Double-check that you are not throwing or returning an error after calling navigateTo. - Make sure your navigation logic is wrapped in nuxtApp.runWithContext if used in a plugin or outside of a component setup. If you follow this pattern and still see the error page, please check if your error handler is being called as expected, and that you are not re-throwing the error after navigation. If you need to clear the error page, you can use the clearError composable as well, but for authentication redirects, handling with navigateTo as shown above is the recommended approach. For more details, see the official Nuxt documentation on custom fetch and error handling Custom useFetch Recipe (Nuxt 4) and Error Handling. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2mo ago
<@520675622830342144> Kapa.ai is still learning and improving, please let me know how I did by reacting below.

Did you find this page helpful?