next.js: not found doesn't catch after dynamic param

Verify canary release

  • I verified that the issue exists in the latest Next.js canary release

Provide environment information

Operating System:
      Platform: linux
      Arch: x64
      Version: Ubuntu 20.04.0 LTS Mon Apr 24 2023 02:05:22 GMT-0300 (Horário Padrão de Brasília)
    Binaries:
      Node: 16.14.2
      npm: 7.17.0
      Yarn: 1.22.19
      pnpm: 8.2.0
    Relevant packages:
      next: 13.3.1-canary.19
      eslint-config-next: N/A
      react: 18.2.0
      react-dom: 18.2.0

Which area(s) of Next.js are affected? (leave empty if unsure)

App directory (appDir: true)

Link to the code that reproduces this issue

https://stackblitz.com/edit/vercel-next-js-pqwxgu?file=app/[locale]/not-found.tsx

To Reproduce

Create a not-found file after a dynamic param [locale] for example, like this: [locale]/not-found.tsx, visit any route like /en-US/yay, it will show next default not found route.

Describe the Bug

It shows next default not found route instead of the custom one created.

Expected Behavior

To show the not found created by the not-found file.

Which browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

No response

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Reactions: 13
  • Comments: 16 (3 by maintainers)

Most upvoted comments

A possible to workaround this if you don’t have any dynamic routes directly below the [lang] is to add a catch-all route (will match only if static routes don’t match):

/[lang]/[...notFound]/page.js

Then inside page.js have a method call:

export default function NotFoundCatchAllPage() { notFound(); }

This will then trigger the segment’s not-found.js instead of the default root one.

Kind of crazy that Next doesn’t support localized 404 pages out of the box. Is there any ETA on a fix for this?

Looking at the reproduction it seems there’s a misunderstanding about how/when not-found.tsx is triggered. The not-found.tsx boundaries currently only apply to calling notFound(). Only app/not-found.tsx is used to render the default 404 page (i.e. when you go to /my-non-existent-page or /dashboard/my-non-existent-page).

Calling notFound() correctly triggers the not-found boundary in app/[locale]/not-found.tsx. The reproduction did not have any notFound() calls so I’ve added one here: https://stackblitz.com/edit/vercel-next-js-sbvl7a?file=app%2F[locale]%2Fpage.tsx and you can see it working when going to /en. It’s currently expected that /en/my-non-existent-page does not match/render app/[locale]/not-found.tsx.

This is definitely something we’re going to add support for in the future but it’s working as expected currently. Would recommend opening a discussion feature request for this change so that we can keep track of interest in the feature.