Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

After initializing the page that throws an error and navigating to other pages, the error view should disappear. #22683

Closed
Warinyourself opened this issue Aug 17, 2023 · 12 comments · Fixed by #25389

Comments

@Warinyourself
Copy link

Environment

Operating System: NixOS
Node Version: v18.16.0
Nuxt Version: 3.6.5
Nitro Version: 2.5.2
Package Manager: pnpm@8.6.0
Builder: vite
User Config: pages, typescript, stylus, app, modules, components, vite
Runtime Modules: -
Build Modules: -

Reproduction

Stackblitz
Github

Describe the bug

Reproduction:

  1. Go to the "Error page".
  2. Reload the page.
  3. Navigate to other pages.
  4. The error view does not disappear.

Mandatory conditions:

  • The ssr property in nuxt.config.ts must be set to false.
  • The showError function must be used in useAsyncData (without the lazy: true).

Expected Behavior:
After initializing the page that throws an error and navigating to other pages, the error view should disappear.

Actual Behavior:
After initializing the page that throws an error and navigating to other pages, the error view does not disappear.

Additional context

No response

Logs

No response

@stackblitz
Copy link

stackblitz bot commented Aug 17, 2023

Fix this issue in StackBlitz Codeflow Start a new pull request in StackBlitz Codeflow.

Copy link
Member

You should clear the error with the clearError composable. It takes an optional redirect for navigation: https://nuxt.com/docs/api/utils/clear-error#clearerror.

@danielroe danielroe closed this as not planned Won't fix, can't repro, duplicate, stale Aug 18, 2023
@Warinyourself
Copy link
Author

@danielroe, yes, of course, but this line of code should delete the error, and it works as expected, except when throwing the error in useAsyncData with ssr:false mode.

You can reproduce the error here.

Additionally, here is a videos for proof:
Expected Behavior (works with ssr:true)
Actual Behavior

@danielroe danielroe reopened this Aug 23, 2023
@pascalwengerter
Copy link
Contributor

Can confirm this issue - we're running Nuxt in SSG mode and the error(.vue) view doesn't disappear upon navigating away using the Header/Footer <NuxtLink>s.

I've tried a workaround (rough sketch below), but that doesn't work as I would expect it...

const error = useError();

onBeforeRouteLeave(async (to) => {
  await navigateTo(to.fullPath);
  error.value = null;
});

@FabianEllenberger
Copy link

Same for me when using an error.vue file like this:

<template>
  <div>
    <Navigation />
    <div class="container mx-auto p-6">
      <h1>{{ error.message }} - {{ error.statusCode }}</h1>
      <button @click="handleError">{{ $t('backToHome') }}</button>
    </div>
  </div>
</template>
<script setup lang="ts">
defineProps({
  error: {
    type: Object,
    default: () => {},
  },
})
const handleError = () => clearError({ redirect: '/' })
</script>

The link that clears the error works, but every link inside the <Navigation> component is not navigating (just changing the url) and the error page stays active.

For a normal 404 error page i would like to not have to manually clear the error on each click, i just want to leave the 404 page via the navigation.

Like it is handled on the nuxt docs: https://nuxt.com/asdfsad

@FabianEllenberger
Copy link

Workaround that works for me is to throw errors inside onMounted instead of just directly after a useFetch:

Works (but no idea why…):

<script setup lang="ts">
const route = useRoute()
const { data } = await useFetch(`/api/movies/${route.params.slug}`)

onMounted(() => {
if (!data.value) {
  throw createError({ statusCode: 404, statusMessage: 'Page Not Found' })
}

})
</script>

Does not work and results in a "frozen" error.vue that blocks any NuxtLink navigation, unsless you use clearError with a redirect like clearError({redirect: '/'}):

<script setup lang="ts">
const route = useRoute()
const { data } = await useFetch(`/api/movies/${route.params.slug}`)
if (!data.value) {
  throw createError({ statusCode: 404, statusMessage: 'Page Not Found' })
}
</script>

@dulnan
Copy link

dulnan commented Oct 27, 2023

Can confirm this is also happening on all our projects. Specifically, we are using a composable that uses createError() to throw 404 errors, among other things:

// ~/pages/foobar.vue

const { data } = await useAsyncData(async () => {
  // do API request
})

const entity = await usePageEntity(data)

entity is guaranteed to be non-null as this point, because the composable throws an error if it isn't available.

Moving the createError() to onMounted() inside the composable would significantly reduce the DX, as the composable would then have to always return entity even if it's null. This would make our page components much more verbose.

@dulnan
Copy link

dulnan commented Oct 27, 2023

For now as a very hacky workaround I've implemented this global middleware:

export default defineNuxtRouteMiddleware((to, from) => {
  const error = useError()

  if (process.client && error.value && to && from && to.path !== from.path) {
    const isOnErrorPage = document.getElementById('nuxt-error-page')
    if (isOnErrorPage) {
      window.location.href = to.fullPath
    }
  }
})

It will just force a full page load when clicking away from the error page. I also added an ID attribute on the root element in my error.vue to make sure the middleware only does its magic when the error page is actually being rendered, to (hopefully) reduce unexpected side effects and other bugs.

@gertjanjansen
Copy link

I'm also encountering this issue. I have a similar situation as @dulnan, but unfortunately the hacky workaround doesn't work either. I think that's because errors that happen on the client aren't accessible through useError. At least, that's what I read on https://masteringnuxt.com/blog/nuxt-3-client-side-error-handling: "Note: Nuxt has composables and utilities like useError and clearError, but these operate on the server error. The error object that NuxtErrorBoundary uses is specific to the instance of the component and only exists on the client-side."

Any progress on this issue? It's been open for quite a while now.

@gal-cernilogar
Copy link
Contributor

gal-cernilogar commented Jan 5, 2024

Had the same issue on a SSG project. Simplest workaround that worked for us was:

<script setup lang="ts">
const route = useRoute();
watch(() => route.fullPath, () => clearError());
</script>

inside error.vue.

Hope it helps

EDIT:
The above didn't actually cover everything so another workaround we came up with was:

const router = useRouter();

const removeNavigationGuard = router.beforeEach(to => {
  removeNavigationGuard();
  clearError({ redirect: to.fullPath });
});

@danielroe
Copy link
Member

Opened a PR to fix. Just one note, after that merges the original reproduction will be resolved, but you do need to ensure <NuxtLayout> isn't the root node of your error.vue. (Wrapping it in a div should be sufficient.)

@pascalwengerter
Copy link
Contributor

Opened a PR to fix. Just one note, after that merges the original reproduction will be resolved, but you do need to ensure <NuxtLayout> isn't the root node of your error.vue. (Wrapping it in a div should be sufficient.)

Awesome, that's great news <3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants