rust-lang / rust-lang/rust-clippy

Use of Display impl of an implementor of std::error::Error

Open
#10,076 2 comments 1 reaction 1 assignee View on GitHub

@sruggier is already working on this.

Since Mar 3, 2026.

A-lint
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.