-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
hyper::Error
prints its first cause in its Display impl, causes duplicate printing in many scenarios
#2771
Comments
Note that #2737 added a |
Note my last paragraph. The existence of To summarize the two reasonable options here:
|
This was previously discussed here #2732 |
It was, but the "fix" there did not address the actual issue. The issue as filed is the same thing I'm complaining about: it should either not print the immediate cause in The basic requirement is |
I provide the rationale in this comment here. The short answer is that I believe the more common case is users that are simply
Please give the benefit of the doubt. We all want what's best, even when what's best isn't crystal clear yet. |
@seanmonstar Your stated rationale supports the idea of changing the behavior of As previously mentioned, if the immediate cause is a public error type then this will break downcasting of that cause, but hyper doesn't seem to make any guarantee as to what the underlying error source is anyway and reporting error chains is vastly more common than downcasting sources. If someone actually needs downcasting then Footnotes
|
Sorry for the confusion, I was in fact advocating for the way hyper currently is. I think the solution is instead that the errors working group and error reporting crates figure out a way to indicate they are going to crawl the source chain and print each out. As I mentioned, I believe it is more common for users to just print the I explored that some in seanmonstar/errors#1. Re-reading that issue, I see it disagrees slightly with my current opinion on what is default. But the rest is still good. |
I'm in agreement here with @seanmonstar. Very few users actually crawl the chain as opposed to just logging the error. The common case works best if behavior remains as it currently is. |
Logging the error often involves crawling the chain.
These are just what I know off the top of my head. Printing the whole chain is extremely common when logging errors. And I don't see how this is in conflict with what you want. Your rationale only matters for the |
I just realized that the error I quoted above ( I understand your rationale for this behavior on Footnotes
|
I work around that like so struct DedupHyperErrorSources {
error: hyper::Error,
}
impl DedupHyperErrorSources {
fn new(error: hyper::Error) -> Self {
Self { error }
}
}
impl fmt::Debug for DedupHyperErrorSources {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.error.fmt(f)
}
}
impl fmt::Display for DedupHyperErrorSources {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.error.message())
}
}
impl std::error::Error for DedupHyperErrorSources {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
if self.error.is_connect() {
// hyper's internal `ConnectError` also includes the source in its `Display` impl but
// otherwise doesn't add anything valuable to the source chain. So we can just skip it.
self.error.source()?.source()
} else {
self.error.source()
}
}
} |
@davidpdrsn Have you confirmed that no other wrapped error has the same behavior? Since I'm tempted to just accept the current Edit: Also, by skipping the |
Also digging through this now, it appears as though the Which is to say, assuming that |
I looked through hyper's errors and didn't find other errors that did this. Whether there are errors elsewhere that exists in hyper's error chain, I'm not certain off. But what I posted works for my use case. |
@davidpdrsn I just looked myself as well and In any case, your solution will lose the message "tcp connect error". Unfortunately I can't wrap this error in another error type that formats the Edit: I suppose I overlooked the idea of just pre-formatting the message into a Edit 2: Oh, even better, my wrapper can just contain another wrapper around the error and access the message through that second wrapper, and that second wrapper can then do the |
I've also run into this issue. I'm indirectly using hyper through tonic and simply wrapping it in |
To wrap up here, this behavior was changed in 1.0. It now only prints the current error, not the source too. |
Version
hyper v0.14.17
Description
hyper::Error
'sDisplay
impl will print its immediate cause in a"{description}: {cause}"
format. The problem is this screws with anything else that tries to print an error along with its causes, as the immediate cause is also the returned value from.source()
.For example, if I were to print an error with
tracing
's built-in support, e.g.error!(err as &dyn StdError, "message")
, the resulting log line includeserr=error trying to connect: tcp connect error: Connection refused (os error 61) err.sources=[tcp connect error: Connection refused (os error 61), Connection refused (os error 61)]
. Or if I wrap this in aneyre::Report
and print that with{:#}
(which includes the cause chain), I geterror trying to connect: tcp connect error: Connection refused (os error 61): tcp connect error: Connection refused (os error 61): Connection refused (os error 61)
which is even more confusing.This appears to be an intentional decision, especially as it has a
.message()
accessor that returns animpl Display
that is just the message. But it's one that is very frustrating. Ideallyhyper::Error
would just not include its cause, relying on the user to opt in to showing causes. Alternatively it could just skip the first cause in the.source()
accessor, though that means users who want to actually inspect that cause (e.g. to downcast it) can't (though in the case of the quoted error, its cause is not a public type and so there's nothing I can reasonably do with it besides just printing it).Changing this behavior will surprise anyone who is currently working around it, though I suspect it will simply produce better behavior for most users who just log the error and move on. My preferred solution of "just don't print the cause" does make the
message()
accessor pointless, though that could simply be deprecated without having to do a breaking change.If you really don't want to make this change, then at least please change the
message()
accessor to actually be animpl StdError + Send + Sync
such that I can then pass that to whatever I'm using that logs causes. The resulting error from this would of course retain the initial cause as thesource()
. Please also do this even if you decide the right solution is to just skip the initial cause insource()
, so I can still get the formatting I want without having to reinvent error chains (especially when dealing with stuff likeeyre::Report
's{:?}
printing).The text was updated successfully, but these errors were encountered: