How to return a custom status code in a server component?
Answered
Mini Rex posted this in #help-forum
Mini RexOP
I wish to respond to an invalid URL query parameter value with a 400 status code. As I understand, returning a custom HTTP status code in an RSC is not possible due to prerendering. But what I’m struggling to understand is how is something like
notFound()
able to be implemented?36 Replies
notFound throws an error which nextjs detects internally and responds with correct status code
Mini RexOP
What I’m asking is why could this not be done for every status code?
@Mini Rex What I’m asking is why could this not be done for every status code?
Giant Angora
if you want another status code then redirect from Middleware
Giant Angora
notFound
name suggests that it will throw 404 status code, that 404 code is used for. so if you need to act on bad query param its mean you need 400 status code that is for bad requestAsian black bear
fwiw missing or incorrect query parameters should NOT return 400.
@Asian black bear fwiw missing or incorrect query parameters should NOT return 400.
Giant Angora
Query params are filters or modifiers, not required input. their absence or invalidity shouldn’t “break” the request, just change or default the behavior.
- 400 → bad HTTP syntax (rare for query params)
- 422 → good syntax, invalid value (more accurate for validation errors)
- 200 with defaults → when the API chooses to be user-friendly
- 400 → bad HTTP syntax (rare for query params)
- 422 → good syntax, invalid value (more accurate for validation errors)
- 200 with defaults → when the API chooses to be user-friendly
i still dont get it why would you need error code if ure going to display the RSC anyway?
@Giant Angora if you want another status code then redirect from Middleware
Mini RexOP
It seems that Next.js restricts the value of the second parameter of
NextResponse.redirect()
to the values 301,302,303,307,308. Using any other value gives the following error: Error [RangeError]: Failed to execute "redirect" on "response": Invalid status code
.@Asian black bear fwiw missing or incorrect query parameters should NOT return 400.
Mini RexOP
Some Stackexchange answers seem to suggest that this is the way to respond to bad query parameters, hence why I’m here
@alfonsüs ardani i still dont get it why would you need error code if ure going to display the RSC anyway?
Mini RexOP
I acknowledge that setting a custom status for a non-API route is somewhat pointless since the only way to actually see it is through the browser’s dev tools. However, it would be strange for the webpage to claim, for instance, that this document is a ‘400 error’ when it doesn’t actually give a 400 status code… whereas a 404 page can say that it’s a 404 page due to the 404 status code and it wouldn’t be lying
I’m fine with the fact that a custom status can’t be achieved because of prerendering, or streaming, or some other technical reason. But what is bugging me is that I can’t wrap my head around how
notFound()
, on a technical level, is able to influence the status codeAsian black bear
Because it throws an error and Next catches it internally and maps it onto a status code.
redirect to
/error/404?message=
which is a route handler which returns html with proper status code@Asian black bear Because it throws an error and Next catches it internally and maps it onto a status code.
Mini RexOP
But it begs the question why that can’t be done for every status code. If someone asks me why my app can’t respond with some custom status code for some situation, how can I explain to them why it isn’t possible? But a 404 somehow is.
@Yi Lon Ma redirect to `/error/404?message=` which is a route handler which returns html with proper status code
Mini RexOP
This idea somewhat works. From a
I guess the point of the thread isn’t to find a hack solution though. I know a supported one doesn’t exist so I have to decide on the best practice for my app. If I decide to use a 200 status code but display only an error message on the page, I’m not sure how I could explain to someone who notices the 200 status and says its a mistake not to use 4XX.
page.tsx
handler route I can redirect to a route.tsx
handler route which fetch
es the original page.tsx
and then return some HTML with a custom status code, but this approach requires a dedicated error page and the redirect changes the URL path. Alternatively, I can have the original route be a route.tsx
that fetch
es a page.tsx
and then returns the HTML and any status code. Funny workaround.I guess the point of the thread isn’t to find a hack solution though. I know a supported one doesn’t exist so I have to decide on the best practice for my app. If I decide to use a 200 status code but display only an error message on the page, I’m not sure how I could explain to someone who notices the 200 status and says its a mistake not to use 4XX.
@Mini Rex But it begs the question why that can’t be done for every status code. If someone asks me why my app can’t respond with some custom status code for some situation, how can I explain to them why it isn’t possible? But a 404 somehow is.
"it would be strange for the webpage to claim, for instance, that this document is a ‘400 error’ when it doesn’t actually give a 400 status code…"
i think it has to do with how nextjs double down on streaming components for loading ui or notfound or what not, it would be weird to return 400 status code after the webpage already send 200 and started rendering layout page.
i think it has to do with how nextjs double down on streaming components for loading ui or notfound or what not, it would be weird to return 400 status code after the webpage already send 200 and started rendering layout page.
not saying that thats a reason to not implement a custom code but it maybe part of the reason why they havent bothered to implement it yet
Giant Angora
actually @Mini Rex you are mixing REST api with RSC
he already know that here https://nextjs-forum.com/post/1428612937899311204#message-1428637843164762122
question is if there are any implication mixing REST api with RSC, if all web-based apis should follow REST and the effect it has if you dont follow REST at all...
nextjs abstracts a lot of things that makes REST api very redundant. true that it feels weird but does it matter?
"But what is bugging me is that I can’t wrap my head around how notFound(), on a technical level, is able to influence the status code"
fwiw nextjs is experimenting other error codes too such as the canary "unauthorized()" function that returns 401
fwiw nextjs is experimenting other error codes too such as the canary "unauthorized()" function that returns 401
@alfonsüs ardani "But what is bugging me is that I can’t wrap my head around how notFound(), on a technical level, is able to influence the status code"
fwiw nextjs is experimenting other error codes too such as the canary "unauthorized()" function that returns 401
Mini RexOP
It would be the only 4XX code throwable from an RSC. 401 is so close to 400 I’m so tempted haha
For the record, TanStack Start has the exact same limitation as Next.js: having a
notFound()
function but no general one for any status code. I just want to be able to explain it. I guess the answer is boiling down to ‘performance reasons’ in these newer frameworks.Asian black bear
The reason is that 400 does not make sense for that context. A GET request has no request body and thus cannot be malformed. Either you hit nothing and automatically get a 404 or you hit a proper route at which point a request cannot be bad.
@Mini Rex For the record, TanStack Start has the exact same limitation as Next.js: having a `notFound()` function but no general one for any status code. I just want to be able to explain it. I guess the answer is boiling down to ‘performance reasons’ in these newer frameworks.
Its not performance reason imo, its architectural logic.
How do you change status code once it has been set?
How do you change status code once it has been set?
You could make a half-working implementation by only supporting status code changes to non streaming non suspensed route but thats really not helpful considering you want to put error("402") in the middle of RSC...
Not to mention, what if 2 RSC arrives at 2 different eror codes? Who gets resolved? Relying on order of execution is unstable especially for reusability
Its just the cost that we ate for the niceness of architecture that we have in app dir.
Else you can use pages dir, i heard its possible there
Else you can use pages dir, i heard its possible there
@Asian black bear The reason is that 400 does not make sense for that context. A GET request has no request body and thus cannot be malformed. Either you hit nothing and automatically get a 404 or you hit a proper route at which point a request cannot be bad.
Mini RexOP
I can’t find official sources for the best practices in dealing with bad query parameters, but it seems logical to send the same status code as the API route would send. I’m here because of [this stack exchange answer](https://ux.stackexchange.com/a/85455/151503) which suggests that 400 is ideal here, even if it is an ‘almost useless detail’.
@alfonsüs ardani Its not performance reason imo, its architectural logic.
How do you change status code once it has been set?
Mini RexOP
However
notFound()
does it… The existence of that function proves it’s apparently possible, and therefore not an issue of logic.you'll need to patch next's codebase to create a custom
badRequest()
function or a custom and dynamic requestError(...)
and do stuff there and use it in your codebase@Mini Rex However `notFound()` does it… The existence of that function proves it’s apparently possible, and therefore not an issue of logic.
Yes but it breaks once you add suspense
Answer
Its still not a accurate way to tell if a route is 404 or 200
@alfonsüs ardani Yes but it breaks once you add suspense
Mini RexOP
Ah I see. I have ample knowledge to explain the situation now