Skip to content

Custom error.tsx page is not rendered for dynamic routes using generateStaticParams / ISR in app router. Pages router 500.tsx is rendered instead #62046

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

Open
bkrajewski94 opened this issue Feb 14, 2024 · 12 comments
Labels
bug Issue was opened via the bug report template.

Comments

@bkrajewski94
Copy link

bkrajewski94 commented Feb 14, 2024

Link to the code that reproduces this issue

https://github.com/bkrajewski94/next-isr-error-page-bug

To Reproduce

  1. Install dependencies with npm install
  2. Build the application with npm run build
  3. Start the application npm start
  4. Navigate to localhost:3000/test

Current vs. Expected behavior

If you use generateStaticParams inside a dynamic route like [slug]/page.tsx, none of the custom error.tsx/global-error.tsx pages will be displayed in case of an error. What you'll see instead is the NextJS inbuilt error page
image

In the below example I used generateStaticParams to implement ISR (on request static generation):

// src/app/[slug]/page.tsx

async function getData() {
  const res = await fetch("https://api.example.com/...");

  if (!res.ok) {
    // This will activate the closest `error.js` Error Boundary
    throw new Error("Failed to fetch data");
  }

  return res.json();
}

export default async function Page({ slug }: any) {
  const data = await getData();

  return (
    <main>
      <div>{slug}</div>
      <div>{JSON.stringify(data)}</div>
    </main>
  );
}

// error.tsx is not rendered when:
export function generateStaticParams() {
  return [];
}

// error.tsx is rendered correctly when instead of generateStaticParams I use:
// export const dynamic = "force-dynamic";

It only breaks if you build your application (works fine on devserver).
As you can imagine it can be a big problem when you'd like to e.g. render a custom error page, or log error to an external system inside the error boundary.

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 23.0.0: Fri Sep 15 14:41:43 PDT 2023; root:xnu-10002.1.13~1/RELEASE_ARM64_T6000
Binaries:
  Node: 20.10.0
  npm: 10.2.3
  Yarn: 1.22.21
  pnpm: 7.1.0
Relevant Packages:
  next: 14.1.1-canary.52 // Latest available version is detected (14.1.1-canary.52).
  eslint-config-next: 14.1.0
  react: 18.2.0
  react-dom: 18.2.0
  typescript: 5.3.3
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

App Router

Which stage(s) are affected? (Select all that apply)

next build (local), next start (local), Other (Deployed)

Additional context

No response

@bkrajewski94 bkrajewski94 added the bug Issue was opened via the bug report template. label Feb 14, 2024
@marlonschlosshauer
Copy link

I stumbled across this today, too, but for the 404 pages.

// src/app/[[...slug]]/page.tsx
export function generateStaticParams() {
  return ["home", "about", "career"].map((slug) => ({ slug: [slug] }));
}

export const dynamicParams = false;

export default function Page({ params }: any) {
  const { slug } = params;
  return <div>{slug}.</div>;
}
// src/app/[[...slug]]/not-found.tsx
export default function NotFound() {
  return <div>this page will never be rendered</div>;
}

Accessing /home etc. works but if you enter e.g /test you'll get the default Next 404 page, instead of the specific not-found.tsx for that route.

Repro: https://github.com/marlonschlosshauer/next-dynamic-routes-static-params-not-found

@bkrajewski94
Copy link
Author

Hi @marlonschlosshauer, I've managed to better identify the problem and I've found a workaround, although it's not the best one.

What I've found out is that when /app router dynamic route throws an error, for some reason the /pages router 500.js page is rendered instead of the /app routers error.js / global-error.js.

I guess it could be the same for app/not-found.js, so what you could do is you could add 404.js page inside the page router, and see if it works.

@bkrajewski94 bkrajewski94 changed the title Custom error.tsx page is not rendered for dynamic routes using generateStaticParams / ISR Custom error.tsx page is not rendered for dynamic routes using generateStaticParams / ISR in app router. Pages router 500.tsx is rendered instead Feb 15, 2024
@marlonschlosshauer
Copy link

Hey @bkrajewski94 Thanks for the suggestion! Interestingly enough, that (thankfully?) didn't fix it for me. Running the app in dev mode also indicates that it is still using the global app directory 404 page:

 ✓ Compiled /[[...slug]] in 434ms (408 modules)
 ✓ Compiled /not-found in 84ms (413 modules)

Maybe we're having different issues after all. I work around for my issue would be to just use the default /not-found.js, although I'd like to avoid that to circumvent needing an additional, top-level, layout.

@bkrajewski94
Copy link
Author

I've played around with it a bit by implementing my own error boundary. I think that the issue is caused by componentDidCatch not being executed in case of ISR

@coffeecupjapan
Copy link
Contributor

@marlonschlosshauer
It seems like Next.js only recognizes 404 page in root directory and cannot recognize 404 page in dynamic directory.

validFileMatcher.isAppRouterPage(absolutePath) ||
// For now we only collect the root /not-found page in the app
// directory as the 404 fallback
validFileMatcher.isRootNotFound(absolutePath),

But it is For now so you can wait until core team to tackle with this issue.
Code above is only a build phase problem, but there are also server side and client side problems and I cannot pick all dependencies of this change. Sorry.

You only can customize root directory 404 page for now. See doc.

@sroebert
Copy link

Having the same issue as well, with static routes and the app router. If I add a pages folder with 500.tsx, that error component is rendered instead.

@Zvanderschyff
Copy link

Having the same issues when running a Production build. Had to create a _error.js file in the page router in order to have a custom error show when there is a server side error. The documentation states: If an error is thrown inside a Server Component, Next.js will forward an Error object (stripped of sensitive error information in production) to the nearest error.js file as the error prop.

I don't know if that means that if you have an error.js in your app router that it is supposed to use that for server errors too or if it just means that it sends through an Error object and we need to somehow handle that.

Funny enough when using the error.js in App router; when there is a client side error it doesn't display the custom error but instead a blank page and in the console I have a "more hooks rendered than in the previous render" error. Had to write my own ErrorBoundary in order for client errors to work fine. I believe there is some setState in the ErrorBoundary of Next that is misbehaving.

Hopefully they find a fix soon.

@11Extrano
Copy link

+1 . Why don't internal errors jump to app/error.tsx? It seems that only errors thrown in server-side components will jump to app/error.tsx

@NazPalUA
Copy link

NazPalUA commented Dec 7, 2024

Seems like this is still broken in Next.js 15.0.4 (latest stable).

Tested both locally in production build and on Vercel deploy:

  • Error boundaries work fine without generateStaticParams
  • As soon as generateStaticParams is added (along with dynamicParams = true), error boundaries stop catching errors for dynamic routes (the ones not pre-rendered during build) in production, while working perfectly in dev mode

It's been almost a year and new major version since this was first reported.
Any updates on this?
Would be great to get some clarity on whether this is expected behavior or a bug that needs fixing.

@damnitrahul
Copy link

I'm facing the same issue as @NazPalUA on Next.js 15.1.0
A clarification and/or possible workaround on this would be highly appreciated @leerob

@tamadam
Copy link

tamadam commented Feb 5, 2025

I have the same issue as others. Interestingly, it works fine in Dev mode (npm run dev). However, in production mode, instead of showing the custom error page, I receive the default 500 error template.

Any updates on possible workarounds? @leerob

@fikkatra
Copy link

I can confirm this is still an issue in v15.3.1 with app router and generateStaticParams in production builds. From my tests I can conclude:

  • Errors resulting from either a client component, a server component or from server actions all trigger a default 500 page, even though a custom error.tsx file is in place (in my case it's app/[[...slug]]/error.tsx)
  • If I create a pages/500.tsx file, this custom page is displayed instead of the default one.

Using the pages router to provide the custom error page is a workaround for aesthetic purposes. However it's not ideal to log errors from here, since server actions cannot be used directly from a client component in pages router. This would result in either leaking the api key for the logging service to the client, or provide an api route to log errors (which can easily be flooded by malicious users).

It's been more than a year and in my opinion, this is really core functionality. Any updates or (better) workarounds?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Issue was opened via the bug report template.
Projects
None yet
Development

No branches or pull requests

10 participants