by burntsushi | 2025-12-28 22:28:51+00:00
> I do think that `std::error::Error` is mostly pointless. That's a value judgment, and reasonable people can disagree.

I took it as a statement of fact. It is a factual matter of whether `std::error::Error` has a point to it or not. And it definitively does. I use the error chain in just about every CLI application I've built. It's not even mostly pointless. It's incredibly useful and it provides an interoperable point for libraries to agree upon a single error interface.

And one `Error::provide` is stable, it will be even more useful.

> I've tried to argue that, it can create bigger problems then it solves. It's a trait that only exists on platforms with `std`. That itself is pretty nasty and if you care at all about platforms that aren't like that, you're taking on a lot of build complexity. If you really need this why not just make your own `trait HasCause` which is like a subset of `std::error::Error` functionality, and simply doesn't require `std`?

The `Error` trait has been in `core` for about a year now. So you don't need any build complexity for it.

But you're also talking to someone who does take on the build complexity to make `std::error::Error` trait implementations only available on `std`. (Eventually this complexity will disappear once the MSRV of my library crates is new enough to cover `core::error::Error`.) But... there really isn't that much complexity to it? It's a very common pattern in the ecosystem and I think your words are dramatically overstating the work required here.

> 1) Why does it require `Display` and then not use it?

Because it defines the contract of what an "error" is. Part of that contract is that some kind of message can be generated. If it didn't require `Display`, then it would have to provide its own means for generating a message. It's not a matter of whether it's "used" or not. It's defining a _promise_.

> 2) Displaying it is very simple: `format!("{err}")`. If you want to format the error and it's chain of causes, actually using the `std::error::Error` functionality, the recommended way was to use yet another experimental `error_chain` library. When should we actually do that? When is that appropriate?

Who says it was "the recommended way"? I never recommended `error_chain`.

Writing the code to format the full chain is nearly trivial. I usually use `anyhow` to do that for me, but I've also written it myself when I'm not using `anyhow`.

> Now we have a place where there's two different ways to do the same thing (display an error). Additionally there is controversy and churn around it.

Yes, this is a problem. If something appears in the `Display` of your error type, then it shouldn't also appear in your `Error::source`. This is definitely a risk of getting this wrong if you're writing your error type out by hand. If you're using a library like `thiserror`, then it's much less likely.

> I understand that there's a bright shiny future that people hope it's headed for, where everything around `std::error::Error` is easy and obvious, and we have powerful flexible expressive ergonomic error handling. I was excited about that like 7 years ago, now I just kinda want to change the channel. I'm glad some people still find some benefit in the small improvements that have occurred over time... and I hope in 8 more years there's more to the story than where we are today.

I was very happy with error handling in Rust at 1.0 personally.

I think people got burned by the churn of the error library treadmill. But you didn't have to get on that treadmill. I think a lot of people did because they overstate the costs of write-once boiler plate and understate the costs of picking the wrong foundation for errors.