N
Nuxt2w ago
Mole

useAsyncData - opt out of reactive error handling

I haven't done much research yet on this topic. However, I am hoping you have the experience and can help :) Motivation My job is making sure business brings money. Component-level error boundaries are cool, no question about it. Business and practical UX wise not so much. Details do not matter, what matters is that they are also more costly to design and develop, compared to the old school full page error. Objective I would love my useAsyncData to old-school throw the error instead of requiring the developer to explicitly handle reactive error property. Something akin to { throwErrors: true }, which opts-out of reactive error handling, throws the error and allows me to centrally handle it. Yapping When I search for useAsyncData in the project. Out of hundreds occurrences, most do not handle error at all. Some do, check the value and showError it instantly, ignoring it is reactive. Only few actually uses it correctly. Is the code bad because it omits error handling? Certainly. Should default behavior encourage silent error swallowing. Debatable. Question How are you handling errors which do not justify custom logic
No description
15 Replies
kapa.ai
kapa.ai2w ago
Hi @Mole. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- I understand your concern about error handling with useAsyncData in Nuxt 3. Let me address your question about opting out of reactive error handling. Current Error Handling in useAsyncData By default, useAsyncData captures errors in a reactive error ref rather than throwing them, requiring explicit handling at the component level. This is why you're seeing many instances where developers either ignore the error property or manually call showError. The documentation shows that useAsyncData returns several values including: - data: the result of the async function - error: an error object if data fetching failed - status: a string indicating request status ('idle', 'pending', 'success', 'error') Nuxt Docs - useAsyncData Handling Errors Centrally For your use case of preferring centralized error handling, there are a few approaches: 1. Using createError and showError You can use createError to create an error with metadata and throw it, which will trigger a full-screen error page on the server side:
const { data } = await useAsyncData('key', async () => {
try {
return await $fetch('/api/data')
} catch (e) {
throw createError({
statusCode: 500,
statusMessage: 'Failed to fetch data',
fatal: true
})
}
})
const { data } = await useAsyncData('key', async () => {
try {
return await $fetch('/api/data')
} catch (e) {
throw createError({
statusCode: 500,
statusMessage: 'Failed to fetch data',
fatal: true
})
}
})
The fatal: true property is important for client-side errors to trigger the full-screen error page. Nuxt Docs - createError 2. Check and Redirect Pattern Another pattern seen in the knowledge sources is to check if data exists and navigate accordingly:
const { data, error } = await useAsyncData('data', () => {
return fetchData()
});

if (!data.value) {
navigateTo('/error')
}
const { data, error } = await useAsyncData('data', () => {
return fetchData()
});

if (!data.value) {
navigateTo('/error')
}
This approach is demonstrated in a Stack Overflow post where a user handles authentication errors by redirecting to a login page. Stack Overflow - Handling 401 Errors 3. Server Response Manipulation For server-side rendering, you can directly manipulate the response:
const { data, error } = await useAsyncData('data', () => {
return fetchData().catch(() => {
if (import.meta.server) {
const response = requestEvent.node.res;
if (!response.headersSent) {
response.writeHead(302, {Location: '/error'});
response.end();
}
}
})
});
const { data, error } = await useAsyncData('data', () => {
return fetchData().catch(() => {
if (import.meta.server) {
const response = requestEvent.node.res;
if (!response.headersSent) {
response.writeHead(302, {Location: '/error'});
response.end();
}
}
})
});
Recommendation Since there's no built-in throwErrors option in useAsyncData, I recommend creating a wrapper function around useAsyncData that implements your desired behavior:
const useAsyncDataWithErrorHandling = async (key, handler, options = {}) => {
const result = await useAsyncData(key, async () => {
try {
return await handler()
} catch (e) {
// For fatal errors that should trigger the error page
throw createError({
statusCode: e.statusCode || 500,
statusMessage: e.message || 'An error occurred',
fatal: true
})
}
}, options)

return result
}
const useAsyncDataWithErrorHandling = async (key, handler, options = {}) => {
const result = await useAsyncData(key, async () => {
try {
return await handler()
} catch (e) {
// For fatal errors that should trigger the error page
throw createError({
statusCode: e.statusCode || 500,
statusMessage: e.message || 'An error occurred',
fatal: true
})
}
}, options)

return result
}
This wrapper will centralize your error handling logic while maintaining compatibility with Nuxt's data fetching system. The knowledge sources don't indicate a built-in way to opt out of reactive error handling in useAsyncData, but these approaches should help you achieve centralized error handling in your Nuxt application. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2w ago
<@522852263979384852> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Mole
MoleOP2w ago
It is reasonable one (eg. kappa bot) would think it works. But it does not. Nothing you do inside useAsyncData bypasses the error boundary (ref: https://stackblitz.com/edit/github-mzystala?file=app.vue). A project likely already has a wrapper for API calls, which translates http response into frontend-local error object. But useAsyncData is playing Pokemon, catching 'em all. If you read through the code people post, it almost never handles errors. Sure, "minimal reproduction". I am happy to bet on how many of these "minimal reproductions", which coincidently happen to include a ton of unrelated details, omit error handling on purpose. useAsyncData never throws (ref). People do not understand it. Nuxt team do not understand it (ref, cc @Atinux). Are mere mortals supposed to understand?
dwol
dwol2w ago
I don't fully understand your question. You want to exclude certain errors from being caught by useAsyncData?
Mole
MoleOP2w ago
Pretty much, yes
dwol
dwol2w ago
This is super basic but can't you do something like this?
dwol
dwol2w ago
deetz99
StackBlitz
Nuxt Error Boundary (forked) - StackBlitz
Create a new Nuxt project, module, layer or start from a theme with our collection of starters.
Mole
MoleOP2w ago
In this example, you are handling the error locally (const { error } = useAsyncData(...)). This is 100% proper way to handle it locally. However, you must have the logic to deal with error everywhere you call useAsyncData. What I am looking for is a way to call
const { data } = await useAsyncData(() => $api('/blog/non-existing-slug-or-id')
const { data } = await useAsyncData(() => $api('/blog/non-existing-slug-or-id')
And have it display full page error without having to add anymore local code in the component. No checking error value. You can check the error value, I believe proper way to throw full page error would be adding this code below:
watch(error, (value) => showError(value))
watch(error, (value) => showError(value))
My issue with this is, nobody remembers to check error. And in such cases, I would not want the error to be implicitly swallowed (what is error swallowing - wikipedia). It is a very dangerous practice and should always be intentional.
dwol
dwol2w ago
If you don't want to do this everywhere you call useAsyncData you'll probably need to create a custom wrapper composable with whatever logic you want in there https://nuxt.com/docs/guide/recipes/custom-usefetch#custom-usefetch
Nuxt
Custom useFetch in Nuxt · Recipes
How to create a custom fetcher for calling your external API in Nuxt.
dwol
dwol2w ago
or custom $fetch plugin with onResponseError and use that instead of the provided $fetch
Mole
MoleOP2w ago
^ You would think it works. It does not. useFetch is using useAsyncData internally and thus whatever you throw (eg. using onResponseError) will be simply caught by useAsyncData and provided to you as return value. You could probably wrap useAsyncData, add the error watcher yourself and throw from it. That's why I explicitly said without wrapping, as this approach forces the developer to write what should be framework code in the userland. In addition to already having custom fetch as per docs link you sent. Here is example of wrapped useAsyncData, which mostly works. It does not break out of the scope when called with await. Which I think may cause other issues.
function useMyAsyncData(...params) {
const asyncData = useAsyncData(...params)
watch(asyncData.error, (value) => value && showError(value))
return asyncData
}
function useMyAsyncData(...params) {
const asyncData = useAsyncData(...params)
watch(asyncData.error, (value) => value && showError(value))
return asyncData
}
Atinux
Atinux2w ago
Thank you for your feedback @Mole, I agree that Nuxt 3 error handling is a bit trickier than Nuxt 2 as we have to deal with <Suspense> and stop the rendering of the page on SSR to show the error page. We believed that handling errors at the component level could: - improve the UX as you can show the error with a specific context (and keeping the header/footer/layout) - avoid dealing with concurrency as many components can have data fetching happening But I also understand that it is easy to forget about handling error on each page/component and sometimes rendering a main error page is better than a broken page/component.
Atinux
Atinux2w ago
GitHub
useAsyncData - do not swallow errors · Issue #31743 · nuxt/nuxt
Describe the feature Feature Request Allow useAsyncData to optionally throw error, instead of returning as ref. This should be configurable in nuxt config. With an option to still receive a ref whe...
Atinux
Atinux2w ago
I really appreciate the effort you made in writing down the issue And we will definitely work on making error handling much better for Nuxt
Mole
MoleOP2w ago
Lovely! I have answered in the discussion about the name. We are on the same page about UX, handling locally is great. Sadly it is oftentimes harder in practice than we would like. That's why rendering full-page error as easy to reach fallback would be fantastic. I deeply appreciate the work you put on Nuxt and understand the pains working in new paradigm of Suspense and reactiveness everywhere. ❤️

Did you find this page helpful?