6

I just installed a new Next.js app. It has the following page:

// /pages/articles/[slug].js

import React from 'react'
import { useRouter } from 'next/router'
import ErrorPage from 'next/error'

const Article = (props) => {
  const router = useRouter()
  if (router.isFallback) {
    return <div>Loading..</div>
  }
  if (!props['data']) {
    return <ErrorPage statusCode={404} />
  }
  return (
    <div>
      Article content
    </div>
  )
}

export default Article

export const getStaticProps = async(context) => {
  const slug = context.params.slug
  const res = ["a", "b", "c"].includes(slug)
    ? {
      props: {
        data: slug
      }
    }
    : {
      props: {},
      notFound: true
    }
  return res
}

export const getStaticPaths = async () =>  {
  return {
    paths: [
      { params: { slug: "a" }},
      { params: { slug: "b" }},
      { params: { slug: "c" }}
    ],
    fallback: true
  }
}

When the browser navigates to a non-existing page (e.g. http://localhost:3000/articles/d) then it returns the default nextjs 404 page, as expected.

But the browser network tab shows status 200 for the main document (the 404 error page). The only things in the network tab with status 404 are d.json and 404.js.

I think that the main document should also have 404 status. The getStaticProps docs say about the return value:

  • notFound - An optional boolean value to allow the page to return a 404 status and page

But in this case the page status is 200 and not 404. Is there something else necessary to do to return status 404?

Without fallback the status is 404.

juliomalves
  • 42,130
  • 20
  • 150
  • 146
camcam
  • 2,585
  • 8
  • 49
  • 65

1 Answers1

14

For this specific use case you have to use fallback: 'blocking' instead.

export const getStaticPaths = async () =>  {
  return {
    paths: [
      { params: { slug: "a" }},
      { params: { slug: "b" }},
      { params: { slug: "c" }}
    ],
    fallback: 'blocking'
  }
}

Unlike fallback: true, it will not serve a "fallback" version if the page has not been generated yet. That's why you get the 200 status code currently.

Instead, fallback: 'blocking' will wait for the HTML to be generated before rendering the page - similar to what happens during server-side rendering. This means that if notFound: true is returned from getStaticProps you will get the proper 404 status code for the page request.

juliomalves
  • 42,130
  • 20
  • 150
  • 146
  • So, you can't achieve this with static incremental builds, SSG at time of request. I have TENS of thousands of pages, and can't build them at build time, it would explode the build process... so, I use "fallBack: true", but because of legacy pages, they are still being crawled. So, I need to throw a status of 404 for some of them. Pathing incorrect or whatever.. I take params off of the url and then try to derive data, if its not there... throw 404 status... not working , only on refresh. Any ideas? – james emanon Sep 22 '22 at 23:31
  • 1
    @jamesemanon You can, just use `fallback: 'blocking'`. It will still generate new pages statically at request time. – juliomalves Sep 23 '22 at 07:25