Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ export function getPageHandler(ctx: ServerlessHandlerCtx) {
poweredByHeader,
},
{
private: isPreviewMode,
private: isPreviewMode || renderOpts.isNotFound,
stateful: !!getServerSideProps,
revalidate: renderOpts.revalidate,
}
Expand Down Expand Up @@ -388,7 +388,7 @@ export function getPageHandler(ctx: ServerlessHandlerCtx) {
poweredByHeader,
},
{
private: isPreviewMode,
private: isPreviewMode || renderOpts.isNotFound,
stateful: !!getServerSideProps,
revalidate: renderOpts.revalidate,
}
Expand Down
5 changes: 3 additions & 2 deletions packages/next/next-server/server/next-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1610,7 +1610,8 @@ export default class Server {

const revalidateOptions = !this.renderOpts.dev
? {
private: isPreviewMode,
// When the page is 404 cache-control should not be added
private: isPreviewMode || Boolean(cachedData.isNotFound),
stateful: false, // GSP response
revalidate:
cachedData.curRevalidate !== undefined
Expand Down Expand Up @@ -1838,7 +1839,7 @@ export default class Server {
const revalidateOptions =
!this.renderOpts.dev || (hasServerProps && !isDataReq)
? {
private: isPreviewMode,
private: isPreviewMode || isNotFound,
stateful: !isSSG,
revalidate: sprRevalidate,
}
Expand Down
38 changes: 38 additions & 0 deletions test/integration/404-page/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,44 @@ describe('404 Page Support', () => {
runTests('serverless')
})

it('should revalidate for custom 404 page while stale with ssg', async () => {
await fs.move(pages404, `${pages404}.bak`)
await fs.writeFile(
pages404,
`
const page = () => 'custom 404 page'
export async function getStaticProps() { return { props: {} } }
export default page
`
)
appPort = await findPort()
await nextBuild(appDir)
app = await nextStart(appDir, appPort)
const swrCacheControl = `s-maxage=31536000, stale-while-revalidate`
const res404 = await fetchViaHTTP(appPort, '/404')
const resNext = await fetchViaHTTP(appPort, '/_next/abc')
await fs.remove(pages404)
await fs.move(`${pages404}.bak`, pages404)
await killApp(app)

expect(res404.headers.get('Cache-Control')).toBe(swrCacheControl)
expect(resNext.headers.get('Cache-Control')).toBe(swrCacheControl)
})

it('should revalidate for custom 404 page without ssg', async () => {
appPort = await findPort()
await nextBuild(appDir)
app = await nextStart(appDir, appPort)
const res404 = await fetchViaHTTP(appPort, '/404')
const resNext = await fetchViaHTTP(appPort, '/_next/abc')

expect(res404.headers.get('Cache-Control')).toBe(null)
expect(resNext.headers.get('Cache-Control')).toBe(
'no-cache, no-store, max-age=0, must-revalidate'
)
await killApp(app)
})

it('falls back to _error correctly without pages/404', async () => {
await fs.move(pages404, `${pages404}.bak`)
appPort = await findPort()
Expand Down