-
Notifications
You must be signed in to change notification settings - Fork 213
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
switch to using custom error types, rather than generic anyhow::Error #2741
Comments
Could you be more specific to which error return values you would like to match on for different failure cases? In general you are right, and as iroh moves towards 1.0 we probably also should migrate to more specific error types. On the other hand we really need this to be guided by application needs rather than enumerate all the current failure types, as that would lead to breaking the API on every release. If we were to use a custom error type right now things would probably be a single opaque error type, which is just like anyhow, but worse. So far in our own uses we have not needed to distinguish error types, but this doesn't mean there isn't a need! This is why to move this forward we really need specific APIs with specific usecases called out for needing a custom error type. We'd really appreciate your input on this. |
So I am just starting out using iroh, and only because IPFS is not usable in Rust, because there is no machine-readable API specification that I can program against. So all of what the following refers to is very much hacked together in a short time, so take everything with a grain of salt please. My error type in my application (or rather, in the library that becomes my backend implementation), looks like this: #[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Creating Node")]
CreatingNode(#[source] anyhow::Error),
#[error("Spawning Node")]
SpawningNode(#[source] anyhow::Error),
#[error("Failed to get reader")]
GettingReader(#[source] anyhow::Error),
#[error("Failed to put blob")]
PutBlobError(#[source] anyhow::Error),
#[error("Shutdown failed")]
Shutdown(#[from] anyhow::Error),
#[error("Error while serializing metadata to JSON")]
SerdeJson(#[from] serde_json::Error),
#[error("Error while adding bytes")]
AddingBytes(#[source] anyhow::Error),
#[error("Error while reading bytes")]
ReadingBytes(#[source] anyhow::Error),
#[error("Error while putting content object")]
PuttingContent(#[source] Box<Error>),
#[error("Error while putting metadata object")]
PuttingMetadata(#[source] Box<Error>),
} Maybe that helps a bit. As you can probably see from the variant names, half of the cases above are just wrapping errors your API returns. The rest is my application logic errors, that again wrap Remember, I am pretty much in the "sketch things up" phase. |
Hey @matthiasbeyer, great to see you back after our last encounter, Last we spoke, the team came to the working conclusion that we'd stick with anyhow pre-1.0, and transition to
Which means (unless others, especially @dignifiedquire disagree): we need to figure out when to transition over to |
If the rewrite can happen in a day, would it happen earlier? What's blocking it from happening now? Just looked at the source code. There are 146 invocations of Are there any other ways where one can craft a unique Then it goes on Crowdin, or some other place for translation. |
Yes. There is this implementation: So everywhere
There might be even more issues where code has to be re-achitected when something was assuming just Unfortunately it's a little more involved than replacing |
This is the way to go. So the immediate plan looks like this:
Then, we split the 146 variants into different sub errors, or have
The above design is one error. Breakage is unavoidable. Any other concerns? One thing I can think of is that different libraries, e.g. |
I was pointed here from #2860 as a user who complained about anyhow::Error usage in the library. One thing I notice from the discussion here seems to be a baseline assumption that there will be one iroh_base::Error object. This is a mistake, it would mean that anyone who calls A potentially useful approach is to start from public APIs which return anyhow::Error, and convert them into specific error types. For example, #[derive(Debug, thiserror::Error)]
pub enum BindError {
#[error("failed to create magic socket: {0}")]
MagicSocket(anyhow::Error),
#[error("failed to create crypto config: {0}")]
CryptoConfig(anyhow::Error),
} This will need to be refined later on (obviously, since it still contains a bunch of anyhow::Error), but will result in narrow error types covering the specific case that developers may need to handle. Maybe it turns out that all MagicSock errors are actually only Also, it's worth considering that some Results are actually just Options (for example, the "metrics are disabled" error I mentioned earlier should just return an Option), and any functions that move self need to return a custom Result that gives the object back to the caller in order to be able to do anything useful with the Result (iroh_net::endpoint::Endpoint::close is an example). [append] As a quick bonus, I recall this article from Eric Lippert, a designer of C#, which talks about various kinds of errors. Might be useful when considering what should be an error, a panic, or an Option. |
* feat: introduce explicit error handling Ref n0-computer/iroh#2741 * chore: remove unused dependency
Hey there, I just raised n0-computer/iroh-gossip#33, but figured I'd add my 0.0124 AUD to the issue. Normally when I'm writing cli / tui apps, I use color-eyre rather than anyhow (I'm a maintainer of ratatui, so this is pretty often). Color-eyre gives a nicer output, adds more info while handling errors and has a useful panic hook in addition to just providing errors. I noticed that iroh-gossip uses anyhow because the ? operator would not convert the anyhow error to a color-eyre error automatically. This is one of the pain points which would be avoided by moving to custom errors. In general, I've often used thiserror for lib type stuff, but recently have had a chance to look at Snafu. There seems like there's a nice-ish migration pattern from the anything goes error types ( |
Thanks for bringing up snafu, i looked at it a while back, always wanted to look more. |
Replaces `anyhow` errors with concrete error types. One more step towards n0-computer/iroh#2741
collecting some thoughts as I work through error handling
|
Error handling has many aspects, so I updated the title to reflect the original request better. Unfortunately we will not be able to do this in a reasonable manner on stable rust, until someone can figure out proper backtrace propagation when doing custom error types. For more details see #3161 (comment) |
I would love to help fix this, but unfortunately the current state is that custom error types all loose proper backtrace information, both snafu and thiserror fail to provide backtraces to libraries like |
Given that backtrace propagation is being considered a blocking issue (a trade-off for sure, not necessarily the right/wrong choice), I would request that the documentation for fallible methods should be extra careful to document the failure conditions that can happen. As discussed in this task, the key problem with anyhow errors is the lack of |
anyhow is for application error handling, please replace it with dedicated error types in your library crates, so users of these crates can do sane error handling.
The text was updated successfully, but these errors were encountered: