using try/catch with an async method inside a middleware causes a `nuxt instance unavailable` error.
See original GitHub issueEnvironment
- Operating System:
Linux
- Node Version:
v17.9.0
- Nuxt Version:
3.0.0-rc.4
- Package Manager:
npm@8.5.5
- Builder:
vite
- User Config:
modules
,runtimeConfig
,autoImports
- Runtime Modules:
@nuxtjs/tailwindcss@5.1.3
- Build Modules:
-
Reproduction
Visit the /secret
page to see the error:
https://stackblitz.com/edit/nuxt-starter-elpq43?file=middleware%2Fauth.ts
Describe the bug
I’m trying to write an async middleware. However, when catching the rejected promise an error is thrown by nuxt when using navigateTo()
:
async function fetchUser() {
throw new Error();
}
export default defineNuxtRouteMiddleware(async (to, from) => {
let user;
try {
user = await fetchUser();
} catch (e) {
user = null;
}
if (!user) return navigateTo('/');
});
Additional context
No response
Logs
No response
Issue Analytics
- State:
- Created a year ago
- Reactions:2
- Comments:9 (7 by maintainers)
Top Results From Across the Web
Express middleware cannot trap errors thrown by async/await ...
Here, the error will get trapped by try/catch: router. get('/force_async_error/0', async function (req, res, next) { try{ await Promise. reject ...
Read more >Consolidating Error Handling in Nuxt Apps - Zaengle Corp
Here's how we previously handled Axios errors in our Nuxt apps, ... A method in a component async handleSubmit() { try { await...
Read more >Getting Started With Axios In Nuxt - Smashing Magazine
In this tutorial, we will learn how to make a request in our Nuxt.js ... Note that asyncData method can only be used...
Read more >Handling errors in Durable Functions - Azure | Microsoft Learn
Learn how to handle errors in the Durable Functions extension for Azure Functions.
Read more >Error handling in NuxtJS - Damir's Corner
You can log the unhandled errors in server error middleware but you can't handle them there to prevent the static server error page...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Hi! Sorry this issue was left unanswered for so long.
Short story: Calling
navigateTo
in an async context should work out of the box when usingdefineNuxtPlugin()
anddefineNuxtRouteMiddleware()
wrappers but it is not working when using anawait
insidetry/catch
. (Please see the next section below for full story)Here is a quick solution: (Update: upstream issue fixed. You probably don’t need this workaround anymore! Just update the lockfile.)
useNuxtApp
before any async callnavigateTo
viacallWithNuxt
utility from#app
.Updated sandbox: https://stackblitz.com/edit/nuxt-starter-u5esgu?file=middleware%2Fauth.ts,app.vue
And the story…
Let me explain what happens when using
navigateTo
inside an async function and after async/await and how composables work.The way Vue.js composition API (and Nuxt composables similarly) work is depending on an implicit context. During the lifecycle, vue sets the temporary instance of the current component (and nuxt temporary instance of nuxtApp) to a global variable and unsets it in same tick. When rendering on the server side, there are multiple requests from different users and nuxtApp running in a same global context. Because of this, nuxt and vue immediately unset this global instance to avoid leaking a shared reference between two users or components.
What it does means? Composition API and Nuxt Composables are only available during lifecycle and in same tick before any async operation:
The classic solution to this, is caching the current instance on first call to a local variable like
const instance = getCurrentInstance()
and use it in next composables but the issue is that any nested composable calls now needs to explicitly accept the instance as an argument and not depend on magical implicit context of composition-api. This is design limitation with composables and not an issue per-se.To overcome this limitation, Vue does some dark magic when compiling our application code and restores context after each call for
<script setup>
:For a better description of what Vue actually does, see https://github.com/unjs/unctx/issues/2#issuecomment-942193723.
In Nuxt, we have an (internal) utility
callWithNuxt
utility that we can use to to restore context similar to how<script setup>
works which i used for solution above.Nuxt 3 internally use unjs/unctx to support composables similar to vue for plugins and middleware. This enabled us to make composables like
navigateTo()
to work without directly passingnuxtApp
to them. This brings in all DX and Performance (of tree-shaking) benefits Vue Composition has to the whole Nuxt framework.With Nuxt composables, we have the same design of Vue Composition API therefore needed a similar solution to magically do this transform. Check out https://github.com/unjs/unctx/issues/2 (Proposal), https://github.com/unjs/unctx/pull/4 (Transform implementation), and https://github.com/nuxt/framework/pull/3884 (Integration to Nuxt).
Vue currently only supports async context restoration for
<script setup>
for async/await usage. For Nuxt, we additionally added magic transform fordefineNuxtPlugin()
anddefineNuxtRouteMiddleware()
! This means when you use them, Nuxt automatically transforms them with context restoration.The…Bug…: The unctx transformation to automatically restore context seems buggy with
try/catch
statements containingawait
which we have to solve in order to remove the requirement of the workaround I suggested above.Upstream fix: https://github.com/unjs/unctx/pull/28