Skip to content

Commit a5e0553

Browse files
committed
Fix(app renderer): set status code to 500 if unexpected error occurs before streaming
1 parent f0f8762 commit a5e0553

File tree

8 files changed

+81
-0
lines changed

8 files changed

+81
-0
lines changed

packages/next/src/server/app-render/app-render.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1616,6 +1616,10 @@ export const renderToHTMLOrFlight: AppPageRender = (
16161616

16171617
const is404 = res.statusCode === 404
16181618

1619+
if (!is404 && !hasRedirectError) {
1620+
res.statusCode = 500
1621+
}
1622+
16191623
// Preserve the existing RSC inline chunks from the page rendering.
16201624
// To avoid the same stream being operated twice, clone the origin stream for error rendering.
16211625
const serverErrorComponentsRenderOpts: typeof serverComponentsRenderOpts =
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
export const revalidate = 0
2+
3+
export default function UnexpectedErrorPage(props) {
4+
// use query param to only throw error during runtime, not build time
5+
if (props.searchParams.error) {
6+
throw new Error('Oh no')
7+
}
8+
return (
9+
<>
10+
<p id="page">/unexpected-error</p>
11+
</>
12+
)
13+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export default function Root({ children }: { children: React.ReactNode }) {
2+
return (
3+
<html>
4+
<body>{children}</body>
5+
</html>
6+
)
7+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function Loading() {
2+
return <p>loading</p>
3+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
export default function UnexpectedErrorPage(props) {
2+
// use query param to only throw error during runtime, not build time
3+
if (props.searchParams.error) {
4+
throw new Error('Oh no')
5+
}
6+
return (
7+
<>
8+
<p id="page">/unexpected-error</p>
9+
</>
10+
)
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
export default function UnexpectedErrorPage(props) {
2+
// use query param to only throw error during runtime, not build time
3+
if (props.searchParams.error) {
4+
throw new Error('Oh no')
5+
}
6+
return (
7+
<>
8+
<p id="page">/unexpected-error</p>
9+
</>
10+
)
11+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/**
2+
* @type {import('next').NextConfig}
3+
*/
4+
const nextConfig = {}
5+
6+
module.exports = nextConfig
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { createNextDescribe } from 'e2e-utils'
2+
3+
createNextDescribe(
4+
'unexpected-error',
5+
{
6+
files: __dirname,
7+
},
8+
({ next }) => {
9+
it('should set response status to 500 for unexpected errors in ssr app route', async () => {
10+
const res = await next.fetch('/ssr-unexpected-error?error=true')
11+
expect(res.status).toBe(500)
12+
})
13+
14+
it('cannot change response status when streaming has started', async () => {
15+
const res = await next.fetch(
16+
'/ssr-unexpected-error-after-streaming?error=true'
17+
)
18+
expect(res.status).toBe(200)
19+
})
20+
21+
it('should set response status to 500 for unexpected errors in isr app route', async () => {
22+
const res = await next.fetch('/isr-unexpected-error?error=true')
23+
expect(res.status).toBe(500)
24+
})
25+
}
26+
)

0 commit comments

Comments
 (0)