-
-
Notifications
You must be signed in to change notification settings - Fork 813
fix: Set content type header for server function errors #4215
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: Set content type header for server function errors #4215
Conversation
Problem ------- When a server function return an error, the content type header is not set. Solution -------- Use the `FromServerFnError::Encoder::CONTENT_TYPE` associated constant to set the content type header on the returned API response. Note: A similar issue occurs if an error is [returned in Leptos's middleware chain](https://github.com/leptos-rs/leptos/blob/b986fe11dc63a803d026f9ccae804e880c2a702b/server_fn/src/middleware/mod.rs#L77). However, I believe resolving that will require adding a field to the `BoxedService`, which would be an API-breaking change.
| ) | ||
| ); | ||
| let content_type = | ||
| <Self::Error as FromServerFnError>::Encoder::CONTENT_TYPE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This formatting is kind of weird, but it's what cargo fmt wants.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I'd prefer to modify error_response() to take and set the content type from the codec, then we wouldn't need to define a content_type function on Response
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would also prefer that, but I was trying to avoid introducing a breaking change. Would you prefer to modify error_response even though it would be a breaking change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it'll be better to have the better api and do the breaking change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, sounds good. I’ll update when I get a chance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated the PR, please take a look when you get a chance. I made a few additional breaking changes that I thought made sense and also resolve the middleware issue I originally tried fixing in #4216.
|
Have you looked at how the Errors are typically returned? If I recall correctly, they're usually not encoded/decoded using the standard logic and may not be valid JSON |
I think they're encoded by the Line 572 in b986fe1
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for taking the time to look into this, it can certainly get a bit tricky parsing the different layers of server fn code.
I think I'd prefer to modify error_response() here to take the codec's content_type and set it on the response. This way we shouldn't need a new associated fn on the Request and Response types
server_fn/Cargo.toml
Outdated
| "futures", | ||
| ], optional = true, workspace = true, default-features = true } | ||
| thiserror = { workspace = true, default-features = true } | ||
| bon = { workspace = true } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd be open to using typed-builder instead, or manually writing the necessary builder code.
|
I think the following semver error is a false positive; I was able to implement it in one of the example crates. https://github.com/leptos-rs/leptos/actions/runs/16836198701/job/47702412558?pr=4215#step:4:320 |
|
Hey, @benwis , can you take a look at the updated PR when you get a chance? Thanks! |
|
Sorry it's been a few days, had some work to tackle. I'm somewhat puzzled by the direction this took, I didn't think another trait like let content_type =
<Self::Error as FromServerFnError>::Encoder::CONTENT_TYPE;Why not just pass the above as a value to |
Returning the data from |
benwis
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few minor nits and a couple deeper questions as we mess with these traits
|
I did, but it doesn’t have to be part of this PR. I think this is basically ready to merge now. I don’t know if we have a section for custom errors for server fns in the book, but I’d put it there. Maybe in the server_fns_axum example
…On Fri, Aug 22, 2025, at 3:02 PM, Spencer Ferris wrote:
***@***.**** commented on this pull request.
In server_fn/src/response/generic.rs <#4215 (comment)>:
> Response::builder()
.status(http::StatusCode::INTERNAL_SERVER_ERROR)
.header(SERVER_FN_ERROR_HEADER, path)
- .body(err.into())
+ .header(header::CONTENT_TYPE, err.content_type)
+ .body(err.body.into())
.unwrap()
I assume by "this" you mean the CatchPanic layer? Where would you like it be mentioned? In a doc comment for the trait method? Or somewhere else?
—
Reply to this email directly, view it on GitHub <#4215 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/ABVBTCMJ7J2EOQ7O2PY7K233O6HN5AVCNFSM6AAAAACDJLEYTWVHI2DSMVQWIX3LMV43YUDVNRWFEZLROVSXG5CSMV3GSZLXHMZTCNBWGMYTKMBSG4>.
You are receiving this because you were mentioned.Message ID: ***@***.***>
|
|
In general I'm fine with this. I would prefer to use It can't be merged until 0.9, given the breaking changes, and there are no plans for 0.9 in the near future, since releasing new breaking versions causes churn that can take the ecosystem a while to catch up to and is therefore kind of annoying for users. I do think it's possible to do it with relatively fewer changes, by using default trait methods. See #4247 for a non-breaking approach, which we could merge into 0.8. (Assuming |
Thanks, @gbj , the non-breaking approach you mentioned is essentially what I did originally. I would like for this to be able to be released relatively soon, so if 0.9 is not planned any time soon I’d prefer to take the non-breaking approach. The breaking approach could be done later when if/when 0.9 is planned. Any objections on that, @benwis ? |
It makes sense to me, sorry to make this a bit complicated. I'm hoping to get a patch release out soon and would love to have at least this partial release in it. |
|
I updated the PR to go back to the original semver-compatible approach and included some (reworded) comment's from @gbj's sample PR. I also opened a separate PR for the semver-incompatible approach. It's based on If things look good please merge when you get the chance because I do not have merge permissions. |
|
The semver check is failing due to a different change that’s already in https://github.com/leptos-rs/leptos/actions/runs/17198851352/job/48793426173?pr=4215 |
|
Looks like the breaking change was reverted in |
|
Hey @benwis , can you merge this PR when you get a chance? I don't have merge permissions. |
|
Thanks for all your work, and for your patience and flexibility! |
Problem
When a server function returns an error, the content-type header is not set.
Solution
In order to set the content-type header in the response, the
FromServerFnError::Encoder::CONTENT_TYPEassociated constant needs to make its way to where the response object is constructed. This PR achieves this with the following changes:content_methodto theRestrait to allow setting theContent-Typeheader for server function error responses.Res::content_methodfrom the server function handler when an error is returned from the app's server fn impl.Note: As mentioned in #4209, this issue also affects Leptos's middleware handlers. Unfortunately, resolving this for middleware requires a semver-incompatible change. The following PR contains a potential approach: #4249
Closes #4209