-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Add shorthand way to return non-IntoResponse errors #3010
base: main
Are you sure you want to change the base?
Conversation
|
I agree with both points. Regarding the second, do you mean via |
I’m very sceptical of changing behaviour based on I do agree that a sensible default might be to avoid ever emitting 500 errors with bodies. But if this is done I’d like to see it done consistently: currently, the status quo is that we don’t strip 500 bodies, as seen in Maybe we could switch everything to logging at some point? I don’t think this is a siginificant loss for development purposes: reading logs is about as easy as reading response bodies, and even easiër if you’re sending the request programmatically. |
Personally, I'm also not a fan of different behavior based on A few things to create follow up issues from (which are out of scope here) I see right now are:
|
I don't think the sensible default should be to avoid emitting 500 errors with bodies, but the sensible default should be not to emit bodies that contain sensible information that can be used by malicious users. What I was trying to achieve with Maybe my expectations are too high. Just moving this into axum-extra could be sufficient. |
I get where you’re coming from with regards to sensitive information. I think that users will prefer to use one consistent method of debugging, whether it be via response bodies or via logs. Since logs are more general, it might be useful to guide them toward that? To this end, consistently stripping bodies of 500 responses could be a benefit, as it encourages not relying on 500 bodies (since they’re likely to be omitted). It also seems a little difficult/opinionated to draw such a line between “sensitive” and “non-sensitive” stuff. But I haven’t put much thought into that. I do agree that 4XX errors should generally be treated as non-sensitive; the difficulty in my eyes is whether non-sensitive 5XX responses make sense as a concept to begin with. |
It's perfectly fine to return non sensitive information in 500 errors. For example, at work, we do that. We can even return some useful information, like: "please contact our support with the id So you're right, the line between sensitive and non-sensitive information can be difficult to draw, and is not tied to the http status. We could embrace tracing yes. It might just be difficult for developers to configure the subscribers as they want. But it's something we can iterate on. |
Having thought a little while about it, I like the always-log (tracing) solution. Idk whether axum has any |
After reading through every suggestion here, my personal preference would also be to embrace tracing. It feels cleaner to me. One question that I still have: When using logging, I see no real point that discourages using this in production, as it simply returns an error and logs it, thus not exposing it to users. Would it still make sense to put it in Edit: One possible problem would be if an error contains sensitive data and that data ends up in the logs. But I am torn wether that is a case of using it improperly. |
By sensitive information, there are actually two kinds:
By looking at what we would log, I don't see any possibility of having personal data in it. So it should be ok to log. |
use std::io::Write; | ||
use tracing::error; | ||
|
||
/// Convenience response to create an error response from a non-IntoResponse error |
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.
/// Convenience response to create an error response from a non-IntoResponse error | |
/// Convenience response to create an error response from a non-[`IntoResponse`] error |
/// Convenience response to create an error response from a non-IntoResponse error | ||
/// | ||
/// This provides a method to quickly respond with an error that does not implement | ||
/// the IntoResponse trait itself. This type should only be used for debugging purposes or internal |
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.
/// the IntoResponse trait itself. This type should only be used for debugging purposes or internal | |
/// the `IntoResponse` trait itself. This type should only be used for debugging purposes or internal |
e = new_e; | ||
error.push(format!(": {e}")) | ||
} | ||
error!("Internal server error: {}", error); |
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.
Tracing has built-in support for dyn Error
s as values you can capture as fields. I think it would be good to ude that here and add an error
field, instead of string-interpolating the error into the message.
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.
Thats very nice, I did not know that.
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.
The %
you added bypasses the dyn Error support.. Did it not compile previously?
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.
Ah okay, was not aware of that. I did it that way because with error!(error = err)
, the compiler complains that a bound is not satisfied:
error[E0277]: the trait bound `T: tracing::Value` is not satisfied
--> axum-extra/src/response/error_response.rs:33:9
|
33 | error!(error = err);
| ^^^^^^^^^^^^^^^^^^^ the trait `tracing::Value` is not implemented for `T`, which is required by `&T: tracing::Value`
|
= note: required for `&T` to implement `tracing::Value`
= note: required for the cast from `&&T` to `&dyn tracing::Value`
= note: this error originates in the macro `$crate::valueset` which comes from the expansion of the macro `error` (in Nightly builds, run with -Z macro-backtrace for more info)
I googled about this and found the approach with %
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.
You need to cast to &dyn Error
. This compiles: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=b08c7457dc0862f279b3b96daa7fca24
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.
That fixes the trait bound, but it then asks me to add a 'static to T. And the CI in cargo hack
still fails
Motivation
There have been some requests for a way to have a shorthand for returning errors as response that themselves do not implement
IntoResponse
. This is especially handy for development and debugging purposes. Closes #2671Solution
Add a new struct
InternalServerError<T>(pub T)
that can wrap anything that implementsError
and create a response from it. The response sets 500 as status code and contains the full error chain with descriptions in the response.As this is potentially undesired behaviour, the provided docs state that this should only be used for debugging purposes.