<p>Rust has two popular packages for augmenting its error handling:</p>
<ul>
<li><p><a href="https://crates.io/crates/anyhow" rel="noreferrer"><strong>anyhow</strong></a>, for libraries, created by David Tolnay.</p>
</li>
<li><p><a href="https://crates.io/crates/thiserror" rel="noreferrer"><strong>thiserror</strong></a>, for applications, created by David Tolnay.</p>
</li>
</ul>
<p>They control how errors are created, annotated, and handled.</p>
<p>Why is this distinction needed? Should it be a consideration when designing a language?</p>

<language-design><error-handling><rust>
Why would a language have different error handling for libraries and applications?
<p>Errors are problems that [thing] decides not to solve. Instead [thing] passes the buck. You need to think about who you are passing the buck to.</p>
<p>If [thing] is a library, it is passing the buck to code. It should make the errors easy for code to use. Error numbers are one example of this, and solve the most basic problem when dealing with errors in code: comparability (<code>404 == 404</code>). Another nice property is backwards compatibility. If errors get more specific in the future, you don't want comparisons to break (see Go's <a href="https://pkg.go.dev/errors#Is" rel="nofollow noreferrer"><code>errors.Is()</code></a>). Yet another nice property is being able to track, through many layers of function calls, which errors are handled and which ones aren't (ex: Java's <code>throws</code>).</p>
<p>If [thing] is an application, it is passing the buck to a human. It should make the errors easy to read. This usually means including as much context as possible. As we add more context to an error, and therefore more information, the question of how to structure it for comparability, compatibility, and safety become more complex.</p>
<p>You can absolutely do both, it's just slow. You have to spend time thinking about which things should be testable together so calling code doesn't have to deal with 100s of similar but not quite identical errors. You have to make sure you are adding enough information so that the user knows exactly what failed. When you decide an error needs more information attached you have to think about how the change would affect existing code. You have to make the information in the error easy for a machine or a human to parse (which usually means writing formatting functions for the humans). In practice, if you make error handling too onerous, programmers won't do it outside of a few this-100%-must-never-fail cases.</p>

CC BY-SA 4.0
2023-07-07T20:07:51.560Z
2023-07-07T20:07:51.560Z
9072997
CC BY-SA 4.0
2024-07-22T17:01:32.980Z
More notably, people developing development application code in which errors arise can receive and respond to feedback from people developing application code to deal with those errors (if they're not writing the client code themselves).  People developing libraries need to decide and commit to what client code will receive, before most of the client code is even written.
supercat
<h2>Libraries require higher &quot;quality&quot; error types</h2>
<h3>The focus of the library (thiserror)</h3>
<p><strong>Libraries are providers of error information.</strong></p>
<p>Libraries tend to use structured errors, such as enums, for subsequent pattern matching processing.</p>
<p>The library cares about the necessary information about errors, and the smaller the overall structure, the better.</p>
<p>It would be great if macros could be provided to simplify this process.</p>
<h3>The focus of the application (anyhow)</h3>
<p><strong>Application are consumers of error information.</strong></p>
<p>The application generally consumes errors directly, and the application does not care about the structure of the error, as long as it can generate detailed error information.</p>
<p>The application doesn't care how to recover from the error, generally it's because the user didn't provide enough information.</p>
<p>The user should supplement the missing information according to the error message and restart the whole process.</p>
<h2>Implications for language design</h2>
<p>Providers need mechanisms like <code>struct</code> + <code>derive macros</code>, while consumers need mechanisms like <code>Error trait</code> + <code>bail/throw/raise</code> macros.</p>

CC BY-SA 4.0
2023-07-06T14:38:56.573Z
2023-07-06T14:38:56.573Z
Aster
<p>People who write applications don't often care whether they have strongly typed errors or not, given that that doesn't influence program behavior. Whether my error is stringly typed or strongly typed, it has no effect on the output, even though ideologically the latter is often better because of the semantic distinctions. For cases like this, <code>anyhow</code> is appropriate, because it allows you to layer stringly-typed context onto errors without much verbosity. <code>thiserror</code>, on the other hand, has support for strongly-typed errors. A user of a library may wish to distinguish based on the type of error in ways the library author cannot anticipate, so having errors be typed works well (because they can be pattern matched on).</p>
<p>I would, however, like to note that the pattern of a single project-wide error enum largely gets rid of the benefits of <code>thiserror</code>-style strongly-typed errors. If a function is doing I/O in multiple places, and both return a <code>crate::Error::Io(std::io::Error)</code>, that is entirely unhelpful for a user to actually distinguish what the error is. For this, I suggest taking a read of <a href="https://sabrinajewson.org/blog/errors" rel="noreferrer">https://sabrinajewson.org/blog/errors</a>, a wonderful article on error locality and adding context to error messages. It's verbose (although, using <code>thiserror</code> or a similar macro for this makes it less so), but I think working towards a concise way of using the patterns shown here is critical to having really good error handling infrastructure.</p>

CC BY-SA 4.0
2023-07-06T14:42:19.143Z
2023-07-06T14:43:21.593Z
2023-07-06T14:43:21.593Z
dawn
<p>Not a Rust expert, but I'll answer this from the perspective of a programmer and as a language designer.</p>
<h2>Applications</h2>
<p>Applications are in a special position: they know whether an error must be handled and how delicately.</p>
<p>Sometimes, applications can just quit on error. I wrote a command-line tool that just printed an error on <code>malloc()</code> failure and exited. That was fine.</p>
<p>Sometimes, applications need to be super careful. I'm sure <code>systemd</code> has to be careful while in the middle of bringing services up.</p>
<h2>Libraries</h2>
<p>Libraries know the same thing that applications do, but <em>only for themselves</em>. There may be other libraries and an application in the same process space.</p>
<p>So a library must handle its own errors properly, but it also must <em>not</em> remove the choice of the application.</p>
<p>IIRC, <code>libgmp</code>, an arbitrary-precision number library, would quit on allocation failure, and that made application authors very sad because their application would suddenly quit without warning, and they couldn't do anything about it short of patching the library.</p>
<p>I have implemented a library myself, and this library does <em>not</em> just quit on allocation failure; it returns the failure.</p>
<h2>Language Design</h2>
<p>As we have seen above, libraries and applications have different concerns regarding error handling.</p>
<p>I believe this is why Rust has those two libraries.</p>
<p>But such error handling should <em>not</em> be built-in. That is a bad design.</p>
<p>Instead, the language should be designed in such a way that the error handling can be implemented as a library. This is hard because the language designer often can't anticipate how the community will want to handle errors, but I think the recent <a href="https://langdev.stackexchange.com/questions/2015/how-can-we-compare-expressive-power-between-two-turing-complete-languages">expressivity</a> question and <a href="https://langdev.stackexchange.com/a/2016/134">David Young's answer</a> provide a great guideline because error handling is a global property of a program that we want to handle as locally as possible.</p>
<p>Essentially, a language that can do this is one that gives a lot of expressive power to libraries.</p>
<p>The fact that Rust has both implemented as libraries is a great testament to how well it was designed in this aspect.</p>

CC BY-SA 4.0
2023-07-06T15:00:25.963Z
2023-07-06T15:00:25.963Z
Gavin D. Howard
CC BY-SA 4.0
2023-07-07T07:01:19.927Z
A further difficulty in error handling is information gathering. The problem there is that an application wants as lightweight as possible a treatment for a failure it expects (and handles), and as a thorough as possible a treatment (backtrace, ...) for a failure it didn't expect and needs to report to the user. How is a library author supposed to handle that? Anyone's guess...
Matthieu M.
# Why would a language have different error handling for libraries and applications?
Posted by: username_0 on 2023-07-06
Rust has two popular packages for augmenting its error handling:

* [**anyhow**](https://crates.io/crates/anyhow), for libraries, created by David Tolnay.
* [**thiserror**](https://crates.io/crates/thiserror), for applications, created by David Tolnay.

They control how errors are created, annotated, and handled.

Why is this distinction needed? Should it be a consideration when designing a language?
**Tags:** language-design error-handling rust
---
## 4 answers
### Answer by username_3 on 2023-07-06. Score: 15 | Accepted answer
## Libraries require higher "quality" error types

### The focus of the library (thiserror)

**Libraries are providers of error information.**

Libraries tend to use structured errors, such as enums, for subsequent pattern matching processing.

The library cares about the necessary information about errors, and the smaller the overall structure, the better.

It would be great if macros could be provided to simplify this process.

### The focus of the application (anyhow)

**Application are consumers of error information.**

The application generally consumes errors directly, and the application does not care about the structure of the error, as long as it can generate detailed error information.

The application doesn't care how to recover from the error, generally it's because the user didn't provide enough information.

The user should supplement the missing information according to the error message and restart the whole process.

## Implications for language design

Providers need mechanisms like `struct` + `derive macros`, while consumers need mechanisms like `Error trait` + `bail/throw/raise` macros.
---
### Answer by username_4 on 2023-07-06. Score: 6
People who write applications don't often care whether they have strongly typed errors or not, given that that doesn't influence program behavior. Whether my error is stringly typed or strongly typed, it has no effect on the output, even though ideologically the latter is often better because of the semantic distinctions. For cases like this, `anyhow` is appropriate, because it allows you to layer stringly-typed context onto errors without much verbosity. `thiserror`, on the other hand, has support for strongly-typed errors. A user of a library may wish to distinguish based on the type of error in ways the library author cannot anticipate, so having errors be typed works well (because they can be pattern matched on).

I would, however, like to note that the pattern of a single project-wide error enum largely gets rid of the benefits of `thiserror`-style strongly-typed errors. If a function is doing I/O in multiple places, and both return a `crate::Error::Io(std::io::Error)`, that is entirely unhelpful for a user to actually distinguish what the error is. For this, I suggest taking a read of <https://sabrinajewson.org/blog/errors>, a wonderful article on error locality and adding context to error messages. It's verbose (although, using `thiserror` or a similar macro for this makes it less so), but I think working towards a concise way of using the patterns shown here is critical to having really good error handling infrastructure.
---
### Answer by username_5 on 2023-07-06. Score: 6
Not a Rust expert, but I'll answer this from the perspective of a programmer and as a language designer.

## Applications

Applications are in a special position: they know whether an error must be handled and how delicately.

Sometimes, applications can just quit on error. I wrote a command-line tool that just printed an error on `malloc()` failure and exited. That was fine.

Sometimes, applications need to be super careful. I'm sure `systemd` has to be careful while in the middle of bringing services up.

## Libraries

Libraries know the same thing that applications do, but *only for themselves*. There may be other libraries and an application in the same process space.

So a library must handle its own errors properly, but it also must *not* remove the choice of the application.

IIRC, `libgmp`, an arbitrary-precision number library, would quit on allocation failure, and that made application authors very sad because their application would suddenly quit without warning, and they couldn't do anything about it short of patching the library.

I have implemented a library myself, and this library does *not* just quit on allocation failure; it returns the failure.

## Language Design

As we have seen above, libraries and applications have different concerns regarding error handling.

I believe this is why Rust has those two libraries.

But such error handling should *not* be built-in. That is a bad design.

Instead, the language should be designed in such a way that the error handling can be implemented as a library. This is hard because the language designer often can't anticipate how the community will want to handle errors, but I think the recent [expressivity](https://langdev.stackexchange.com/questions/2015/how-can-we-compare-expressive-power-between-two-turing-complete-languages) question and [David Young's answer](https://langdev.stackexchange.com/a/2016/134) provide a great guideline because error handling is a global property of a program that we want to handle as locally as possible.

Essentially, a language that can do this is one that gives a lot of expressive power to libraries.

The fact that Rust has both implemented as libraries is a great testament to how well it was designed in this aspect.
> **Comments:**
> **username_6** (2023-07-07): A further difficulty in error handling is information gathering. The problem there is that an application wants as lightweight as possible a treatment for a failure it expects (and handles), and as a thorough as possible a treatment (backtrace, ...) for a failure it didn't expect and needs to report to the user. How is a library author supposed to handle that? Anyone's guess...  
---
### Answer by username_1 on 2023-07-07. Score: 3
Errors are problems that [thing] decides not to solve. Instead [thing] passes the buck. You need to think about who you are passing the buck to.

If [thing] is a library, it is passing the buck to code. It should make the errors easy for code to use. Error numbers are one example of this, and solve the most basic problem when dealing with errors in code: comparability (`404 == 404`). Another nice property is backwards compatibility. If errors get more specific in the future, you don't want comparisons to break (see Go's [`errors.Is()`](https://pkg.go.dev/errors#Is)). Yet another nice property is being able to track, through many layers of function calls, which errors are handled and which ones aren't (ex: Java's `throws`).

If [thing] is an application, it is passing the buck to a human. It should make the errors easy to read. This usually means including as much context as possible. As we add more context to an error, and therefore more information, the question of how to structure it for comparability, compatibility, and safety become more complex.

You can absolutely do both, it's just slow. You have to spend time thinking about which things should be testable together so calling code doesn't have to deal with 100s of similar but not quite identical errors. You have to make sure you are adding enough information so that the user knows exactly what failed. When you decide an error needs more information attached you have to think about how the change would affect existing code. You have to make the information in the error easy for a machine or a human to parse (which usually means writing formatting functions for the humans). In practice, if you make error handling too onerous, programmers won't do it outside of a few this-100%-must-never-fail cases.
> **Comments:**
> **username_2** (2024-07-22): More notably, people developing development application code in which errors arise can receive and respond to feedback from people developing application code to deal with those errors (if they're not writing the client code themselves).  People developing libraries need to decide and commit to what client code will receive, before most of the client code is even written.  
---
