vercel / next.js

The React Framework
https://nextjs.org
MIT License
125.02k stars 26.7k forks source link

ISR page deployed to Vercel does not respect `notFound` if its been previously built #19578

Closed mikaelgson closed 3 years ago

mikaelgson commented 3 years ago

Bug report

Describe the bug

A ISR page, deployed to Vercel, that's been rendered and cached once will never show a 404 again even if notFound: true is returned from getStaticProps.

To Reproduce

  1. Create a new app using npx create-next-app
  2. Create the page pages/[slug].js looking something like this:
export default function PostTemplate({ post: { title }}) {
  return (
    <h1>{title}</h1>
  )
}

export async function getStaticPaths() {
  return {
    paths: [],
    fallback: "blocking",
  }
}

export async function getStaticProps({ params: { slug } }) {
  const res = await fetch(`https://yourapi.com/posts/${slug}`)
  const post = await res.json()

  return {
    props: {
      post
    },
    notFound: !post, // For this example, let's pretend my API returns a nullish value when a post is missing
    revalidate: 1
  }
}
  1. Deploy to Vercel
  2. Publish a post with the slug my-post
  3. Visit yourdeployment.vercel.app/my-post and the post is successfully rendered
  4. Unpublish the post
  5. Reload the page and get a stale version (expected)
  6. Reload again and you will still get the post even though getStaticProps returned notFound: true during the previous revalidation.

Expected behavior

Im expecting the 404 page to be rendered as the previous revalidation returned notFound: true

Screenshots

N/A

System information

Additional context

If i run the same app locally (npm start) and try this, the 404 will get displayed as expected which makes me suspect it might be related to the Vercel platform.

Let me know if you need me to provide an example app or if anything is unclear.

sabigara commented 3 years ago

I think I'm facing the same issue. Even if I delete a post from the DB, the page is still visible on Vercel (updates are applied correctly). Also, it's the same everything working fine with local npm start.

jensonb commented 3 years ago

I believe the previously generated page.html is left in .next/server/pages/page.html and not cleared when the page is rebuilt with notFound: true. I'm experiencing the following behavior locally:

  1. next build && next export of a page with notFound: true fails due to .next/server/pages/page.html not existing
  2. remove notFound: true, now we are able to next build && next export
  3. add notFound: true, now we are still able to next build && next export
  4. remove .next/, now we get a failure again when attempting to next build && next export

The issue I'm seeing is that next export is attempting to look for the built html file for a notFound: true page, and then either failing due to it not existing or incorrectly using the old version if it exists.

iDVB commented 3 years ago

This is a show stopper for us. Our first go with Vercel+NextJS was/is going to be for a job board. Can't have stale jobs still visible. Would love any ideas or work arounds. Happy to lend a hand testing if it helps.

vassbence commented 3 years ago

@iDVB I'd just use client side fetching and no getStatic* until this is fixed, that way there wont be any stale jobs visible for sure (because if on the cliend side fetch your api returns a 404 you can just redirect the user to the 404 page via next/router

Then when this does get fixed just un-comment those getStatic* functions and you are good to go.

iDVB commented 3 years ago

Thanks @vassbence won't that mean the client and server wont match? (Currently using getStaticPaths)

Or that all posting pages will be client only if I remove getStaticPaths?

vassbence commented 3 years ago

@iDVB well to begin with there is automatic static optimization, meaning all files in your pages folder if they dont use getServerSideProps or getInitialProps get rendered into .html.

If you use getStaticProps you can put extra data into these .html "shells", if you use getStaticPaths you can create multiple .html "shells". By "shell" i mean a html file which has the layout and everything in it, only missing the data. (this way your users will have a good UX and your pagespeed will be great, so use placeholder components and avoid content shifting when your data finishes loading)

So what i proposed is to dont use neither getStaticPaths nor getStaticProps, just have a file like /pages/jobs/[id].js. On every request a html file will be sent, which has no job specific data in it, but it has like a react useEffect in it, which fetches the data from your API, and if the API returns a 404 you can redirect the users with next/router

davscro commented 3 years ago

I have same issue, something is wrong with vercel caching I believe. I am always getting STALE response. Screenshot 2021-01-23 at 22 22 32

hlz commented 3 years ago

It seems like the existing resource for a given route is not being purged from or updated on the (Vercel) CDN when a notFound: true is returned.

Is that even possible for a single resource? It seems only redeploys can purge the CDN.

vassbence commented 3 years ago

@hlz notFound: true is supposed to give you the ability to purge a single endpoint, but it is currently bugged, thus this issue.

meerbahadin commented 3 years ago

experiencing same issue

ijjk commented 3 years ago

Hi, this should now be fixed! I'm going to close this issue, if you are still experiencing problems with this please reply with additional information and we can investigate further.

balazsorban44 commented 2 years ago

This issue has been automatically locked due to no recent activity. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.