rust-lang / rust-lang/rust-clippy
Use of Display impl of an implementor of std::error::Error
@sruggier is already working on this.
Since Mar 3, 2026.
- Dominant language
- Rust
- Stars
- 13.5k
- Forks
- 2.2k
- Avg merge
- 2d 10h
- Merged PRs (30d)
- 32
Description
What it does
Lint on any use of the Display impl of a type which also implmenets std::error::Error. Including uses of an error e with format!("{}", e), write!("{}", e), e.to_string(), &e as &dyn Display.
Recommends the use of an error reporting facility which should chase down the .source()s and prints them too.
As per the Rust Error Handling Working Group recommendations: https://blog.rust-lang.org/inside-rust/2021/07/01/What-the-error-handling-project-group-is-working-towards.html
Lint Name
erorr-display-without-source-report
Category
suspicious
Advantage
When a codebase follows the EHWG recommendation, an Error's Display impl does not print information from the .source() error, if there is one. Without the use of an error reporter, this information is simply elided.
With the common error handling style of having a custom error enum, with lower layers' errors as .source() (eg, #[source] from thiserror), this leads to vacuous error messages which explain only the context of the failure, but not the actual error.
Because all errors must impl Display, it is very easy to accidentally do this. Printing things with {} in log messages, CLI stderr messages, and so on, is very natural - but with the EHWG recommendation it is wrong for an Error which might have a .source().
Drawbacks
The Rust EHWG recommendation is not (as far as I can tell) fully settlted official policy? And there are downsides to the recommendation. So some projects will do things differently to the recommendation.
There will be projects with a single simple error type whose Display impl is perfect.
So this lint is a matter or project error reporting policy. It should probaby be off by default.
An actual error reporting facility which prints the .source() errors will need to use the Display impls of the errors it encounters, so will need to locally suppress this lint in its implementation.
Example
This code:
impl Cache {
fn fetch(obj: Id) -> Result<Option<Thing>> { ... }
}
let reuse_cached_thing: Option<Thing> = cache.fetch(object_identifier)
.unwrap_or_else(|error| {
warn!("could not access cache, recalculating everything: {}", &error);
None
});
might print a message like: could not access cache, recalculating everything: IO error.
In a project following EHWG guidelines, this should be written as:
// provides `.report()` for errors; if EHWG work succeds, there'll be one in std
use our_error_reporting_module::ErrorReport;
let reuse_cached_thing: Option<Thing> = cache.fetch(object_identifier)
.unwrap_or_else(|error| {
warn!("could not access cache, recalculating everything: {}", error.report());
None
});
which might print a message like: could not access cache, recalculating everything: IO error: "/var/cache/thing.cache": Permission denied.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.