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

next/navigation notFound() function do not apply HTTP 404 status code #51021

Closed
1 task done
robinComa opened this issue Jun 9, 2023 · 24 comments · Fixed by #63731
Closed
1 task done

next/navigation notFound() function do not apply HTTP 404 status code #51021

robinComa opened this issue Jun 9, 2023 · 24 comments · Fixed by #63731
Labels
area: app App directory (appDir: true) bug Issue was opened via the bug report template. locked Navigation Related to Next.js linking (e.g., <Link>) and navigation.

Comments

@robinComa
Copy link

Verify canary release

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

Provide environment information

Operating System:
      Platform: darwin
      Arch: x64
      Version: Darwin Kernel Version 22.3.0: Mon Jan 30 20:42:11 PST 2023; root:xnu-8792.81.3~2/RELEASE_X86_64
    Binaries:
      Node: 18.13.0
      npm: 8.19.3
      Yarn: N/A
      pnpm: N/A
    Relevant packages:
      next: 13.4.4
      eslint-config-next: 13.3.0
      react: 18.2.0
      react-dom: 18.2.0
      typescript: 5.0.4

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

App directory (appDir: true), Routing (next/router, next/navigation, next/link)

Link to the code that reproduces this issue or a replay of the bug

https://codesandbox.io/p/sandbox/cranky-pine-f9s292?file=%2Fapp%2Fpage.tsx%3A1%2C1

To Reproduce

const BlogPage = async ({ params }: { params: { categorySlug: string; blogSlug: string; locale: string } }) => {
  const blog = (
    await dataService.collection<{ blogs: Blog[] }>('Blog', params.locale, {
      filters: {
        blog_category: {
          slug: { eq: params.categorySlug },
        },
        slug: { eq: params.blogSlug },
      },
    })
  ).blogs?.[0];

  if (!blog) {
    // Here the issue
    notFound();
  }

  return <>{JSON.stringify(blog, null, 2)}</>;
}

Describe the Bug

When notFound is called, the 404 page is correctly displayed, but the status is 200 :

image

Expected Behavior

The HTTP status code should be 404

Which browser are you using? (if relevant)

Chrome Version 114.0.5735.106 (Build officiel) (x86_64)

How are you deploying your application? (if relevant)

next start

@robinComa robinComa added the bug Issue was opened via the bug report template. label Jun 9, 2023
@github-actions github-actions bot added area: app App directory (appDir: true) Navigation Related to Next.js linking (e.g., <Link>) and navigation. labels Jun 9, 2023
@fab1an
Copy link

fab1an commented Jul 5, 2023

Is there a workaround for this? Will this be fixed?

@caiolrm
Copy link

caiolrm commented Jul 21, 2023

@fab1an @robinComa

Two things were causing this behavior on my project:

  • I was using an instant loading state (loading.tsx file on the same level as the page.tsx). I don't know the specifics, but it does make sense because the loading appears before anything else, so the server needs to send some status code.

  • I was implementing a client component that functioned as a wrapper on the whole layout, so any rendered page used it. It was a provider for i18n values, I didn't go deeper into how it interacted with everything else to cause the wrong status code to be sent, but just removing it works.

Anyway, hope this is relevant to someone.

@fab1an
Copy link

fab1an commented Jul 24, 2023

@caiolrm Thank you for the tipp. I just removed the dynamic route and copy and pasted all files for every [id] that I need to support.

@fab1an
Copy link

fab1an commented Aug 23, 2023

@ijjk Sorry for involving you, but will this ever be fixed? This is a terrible, reproducible bug, that's been open for half a year.

Wrong status-codes served by a webserver should be a core concern.

The only way to workaround it is to not use dynamic routes. At that point I can go back to nginx/apache2.

@Enngage
Copy link

Enngage commented Aug 29, 2023

Same here... Are we seriously not able to set 404 status codes? The docs for notFound says:

/**
 * When used in a React server component, this will set the status code to 404.
 * When used in a custom app route it will just send a 404 status.
 */
export declare function notFound(): never;

But it clearly doesn't work.

@fab1an
Copy link

fab1an commented Sep 5, 2023

@Enngage The issue is with the compbination of caching and dynamic routes.

If you route uses notFound() AND contains an id like [id] it will serve 404 on the first load, but 200 on the subsequent cached loads.

I suspect this is why it wasn't fixed yet. It is too complex to reproduce.

@Enngage
Copy link

Enngage commented Sep 5, 2023

@Enngage The issue is with the compbination of caching and dynamic routes.

If you route uses notFound() AND contains an id like [id] it will serve 404 on the first load, but 200 on the subsequent cached loads.

I suspect this is why it wasn't fixed yet. It is too complex to reproduce.

Hey, it doesn't return 404 on first load... that's the problem because then google indexes the page. It's true we are using dynamic routes with url parameters.

We actually "solved" it by creating a "/404" route and redirected notFound items to this route manually. The /404 route seems special as it applies the 404 status code, but I haven't found it in docs. It was likely there in the old pages router, but not with the new one. It's all bit odd.

@fab1an
Copy link

fab1an commented Sep 6, 2023

@Enngage So you are using redirect to send 307 to the user, which then redirects to a 404 page. Are you sure this is not hurting SEO?

@Enngage
Copy link

Enngage commented Sep 6, 2023

@Enngage So you are using redirect to send 307 to the user, which then redirects to a 404 page. Are you sure this is not hurting SEO?

We are redirecting from server straight to '/404' route which applies the 404. Its the only way we could achieve 404 response status code and stop google from indexing every single path even if it does not exist.

I wish the 'notFound' method worked as documented, but it doesn't.

@fab1an
Copy link

fab1an commented Sep 6, 2023 via email

@Enngage
Copy link

Enngage commented Sep 6, 2023

Can you show us the function you use to do the redirect?

We are using redirect -> import { redirect } from 'next/navigation';

@externl
Copy link

externl commented Sep 17, 2023

This bug seems like a huge pain. Maybe I'm missing something, but how are you supposed to use dynamic routes if they can't be 404'd?

@fab1an
Copy link

fab1an commented Sep 19, 2023

Is this also fixed by #55542?

@MaciejWira
Copy link

@caiolrm , thanks for the tip! I removed loading.tsx and it worked.

@sabaMohamadii
Copy link

I have the same issue , i call notFound() but my doc of page is return 200 status code , how can change that to 404 ?????

@Sitiapp
Copy link

Sitiapp commented Feb 6, 2024

Next js 14 is so popular i wonder how such an issue is still present on the framework logic.. please put this as high priority we need 404 status code after loading not found pages!

@leesaxby
Copy link

leesaxby commented Feb 8, 2024

We were also experiencing this issue and as mentioned by @caiolrm, removing the use client providers we had wrapping our component hierarchy fixed the issue.

Digging a little deeper we found the issue was actually being caused by useEffects in the client providers that were making async calls.
Refactoring to remove these useEffects fixed the issue and the "not found" page now returns a status code of 404.

This also incidentally fixed an issue we were experiencing with generateMetadata not rendering the app if there was a delay when fetching dynamic meta data.

@GXM245
Copy link

GXM245 commented Feb 21, 2024

Also experiencing the same issue. Our structure looks like this and this will recreate the problem:

app
-> [slug-route]
-> homepage
-> another-static-page
-> another-static-page
-> loading.js
-> not-found.js

By removing the loading.js page the issue goes away and 404 is returned instead of 200 status for the not found page (for both client side and server side).

This is a serious issue as it forces you to choose between User Experience (loading page) and SEO (where 404s are critical for crawl budget and clarity) - two of the main reasons we chose Next JS. If anyone can look into/resolve this (e.g. @balazsorban44 ), we'd be very grateful.

@MaciejWira
Copy link

@GXM245, as a compromise - you can use something like progress bar: https://www.npmjs.com/package/next13-progressbar?activeTab=code (or write something similar by yourself). You can see such solution on github too. So there is no loading.js, but there is still an effect of loading state when clicking internal links.

@GXM245
Copy link

GXM245 commented Feb 26, 2024

Thanks @MaciejWira! I'll take a closer look at that - and yes, you're right, the most suitable option at this point would be to write something ourselves. I wonder how many of us have similar setups but unaware that our pages are, in fact, returning a 200 when they should be a 404. I only discovered this myself after a SEO crawl where a load of pages I expected to be a 404 were returning a 200.

@timneutkens would you be able to lend us your ear on this one? This is quite fundamental to the response codes that core Next JS functionality returns.

@Javad9s
Copy link

Javad9s commented Mar 15, 2024

So right now Nextjs starts streaming data immediately with loading.js and because how the web works it has to have a status code 200. Later on while processing the data we decide it should be a notfound (which is cool btw) and can't change the status code.
I suggest devs expose an experimental flag in NextConfig so that people can opt out of loading.js only if route is dynamic or even if it uses some special function that requires a change in status code (e.g. notfound, forbidden)
Like experimental.ignoreSuspenseForStatus Code

@danjiro
Copy link

danjiro commented Mar 19, 2024

the same issue with redirect() where it will have a status code of 200 instead of 307. This is a pretty big issue SEO-wise

@KurtRogers
Copy link

Lvw

huozhi added a commit that referenced this issue Mar 27, 2024
### What

In static generation phase of app page, if there's any case that we're
receiving 3xx/4xx status code from the response, we 're setting it into
the static generation meta now to make sure they're still returning the
same status after build.

### Why

During static generation if there's any 3xx/4xx status code that is set
in the response, we should respect to it, such as the ones caused by
using `notFound()` to mark as 404 response or `redirect` to mark as
`307` response.

Closes NEXT-2895
Fixes #51021
Fixes #62228
Copy link
Contributor

This closed issue has been automatically locked because it had no new activity for 2 weeks. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 11, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: app App directory (appDir: true) bug Issue was opened via the bug report template. locked Navigation Related to Next.js linking (e.g., <Link>) and navigation.
Projects
None yet
Development

Successfully merging a pull request may close this issue.