You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Wait another 60 seconds, and refresh the page again
Wait another 30 seconds, and refresh the page again
Current vs. Expected behavior
Current
Currently, ISR produces an incorrect 404 status code when restoring from the cache if the previous response was a 404. This error occurs when the page content is resolved normally without the existence of __next_error__ in the HTML anymore, due to a previous error.
The 404 status code remains until either revalidatePath or revalidateTag is called.
Expected
The expected behaviour is that the previous cache should be ignored during revalidation, and a fresh 200 status code is generated instead of reusing the old one.
Provide environment information
Operating System:
Platform: darwin
Arch: arm64
Version: Darwin Kernel Version 24.4.0: Wed Mar 19 21:17:25 PDT 2025; root:xnu-11417.101.15~1/RELEASE_ARM64_T6020
Available memory (MB): 32768
Available CPU cores: 12
Binaries:
Node: 22.13.1
npm: 10.9.2
Yarn: 1.22.19
pnpm: 9.15.9
Relevant Packages:
next: 15.3.1 // Latest available version is detected (15.3.1).
eslint-config-next: 15.3.1
react: 19.1.0
react-dom: 19.1.0
typescript: 5.8.3
Next.js Config:
output: N/A
Which area(s) are affected? (Select all that apply)
Not Found, Runtime
Which stage(s) are affected? (Select all that apply)
next start (local)
Additional context
I haven't been able to track down the root cause yet, but I was able to patch packages/next/src/server/base-server.ts locally.
There is an assumption that a 200 status code should be present, but because the previous response cache is used to fill in some fields, 404 is also possible. See my patch below.
diff --git a/dist/esm/server/base-server.js b/dist/esm/server/base-server.js
index 37f85b41274b2e32ab9551a4e1e7d2e4fcbe0045..1ef62fda97224fbcb60c94286865e094d95ebb28 100644
--- a/dist/esm/server/base-server.js
+++ b/dist/esm/server/base-server.js
@@ -2144,7 +2144,11 @@ export default class Server {
// from the response because it should always be 200. This should be gated
// behind the experimental PPR flag.
if (cachedData.status && (!isRSCRequest || !isRoutePPREnabled)) {
- res.statusCode = cachedData.status;
+ res.statusCode =
+ !cachedData.html.isDynamic &&
+ cachedData.html.toUnchunkedString().includes('__next_error__')
+ ? 404
+ : 200;
}
// Mark that the request did postpone.
if (didPostpone) {
diff --git a/dist/server/base-server.js b/dist/server/base-server.js
index ae2c3bb28e5ab33b57322210e4b94be2f5907267..52758fd0b7bcada9b3ccb361f9cdb98ca621e92b 100644
--- a/dist/server/base-server.js
+++ b/dist/server/base-server.js
@@ -2213,7 +2213,11 @@ class Server {
// from the response because it should always be 200. This should be gated
// behind the experimental PPR flag.
if (cachedData.status && (!isRSCRequest || !isRoutePPREnabled)) {
- res.statusCode = cachedData.status;
+ res.statusCode =
+ !cachedData.html.isDynamic &&
+ cachedData.html.toUnchunkedString().includes('__next_error__')
+ ? 404
+ : 200;
}
// Mark that the request did postpone.
if (didPostpone) {
I don't believe this patch causes any side effects. However, because the assumption is that only a 200 status code should be present, there is no way to predict what other possible status codes might be present. In theory, only 200 and 404 should be possible, but given app-render runtime seems to respond incorrectly, a more robust check needs to exist here to validate the outcome before the handler responds.
EDIT
Upon further digging, I suspect the following app-render status code checks are related, given the lack of additional places where res.statusCode is set.
I suspect app-render doesn't have the proper context to determine when the status code needs to remain a 200, and simply sets it to 404 because of the previous error.
The text was updated successfully, but these errors were encountered:
Link to the code that reproduces this issue
https://github.com/cshawaus/notfound-isr-status-code
To Reproduce
next build
)next start
)Current vs. Expected behavior
Current
Currently, ISR produces an incorrect
404
status code when restoring from the cache if the previous response was a404
. This error occurs when the page content is resolved normally without the existence of__next_error__
in the HTML anymore, due to a previous error.The
404
status code remains until eitherrevalidatePath
orrevalidateTag
is called.Expected
The expected behaviour is that the previous cache should be ignored during revalidation, and a fresh
200
status code is generated instead of reusing the old one.Provide environment information
Operating System: Platform: darwin Arch: arm64 Version: Darwin Kernel Version 24.4.0: Wed Mar 19 21:17:25 PDT 2025; root:xnu-11417.101.15~1/RELEASE_ARM64_T6020 Available memory (MB): 32768 Available CPU cores: 12 Binaries: Node: 22.13.1 npm: 10.9.2 Yarn: 1.22.19 pnpm: 9.15.9 Relevant Packages: next: 15.3.1 // Latest available version is detected (15.3.1). eslint-config-next: 15.3.1 react: 19.1.0 react-dom: 19.1.0 typescript: 5.8.3 Next.js Config: output: N/A
Which area(s) are affected? (Select all that apply)
Not Found, Runtime
Which stage(s) are affected? (Select all that apply)
next start (local)
Additional context
I haven't been able to track down the root cause yet, but I was able to patch
packages/next/src/server/base-server.ts
locally.next.js/packages/next/src/server/base-server.ts
Lines 3566 to 3571 in a556825
There is an assumption that a 200 status code should be present, but because the previous response cache is used to fill in some fields, 404 is also possible. See my patch below.
I don't believe this patch causes any side effects. However, because the assumption is that only a 200 status code should be present, there is no way to predict what other possible status codes might be present. In theory, only 200 and 404 should be possible, but given
app-render
runtime seems to respond incorrectly, a more robust check needs to exist here to validate the outcome before the handler responds.EDIT
Upon further digging, I suspect the following
app-render
status code checks are related, given the lack of additional places whereres.statusCode
is set.next.js/packages/next/src/server/app-render/app-render.tsx
Line 2050 in a556825
next.js/packages/next/src/server/app-render/app-render.tsx
Line 4008 in a556825
I suspect
app-render
doesn't have the proper context to determine when the status code needs to remain a200
, and simply sets it to404
because of the previous error.The text was updated successfully, but these errors were encountered: