eyre-rs / eyre Goto Github PK
View Code? Open in Web Editor NEWA trait object based error handling type for easy idiomatic error handling and reporting in Rust applications
License: Apache License 2.0
A trait object based error handling type for easy idiomatic error handling and reporting in Rust applications
License: Apache License 2.0
When testing with RUSTFLAGS=-Zallow-features= cargo +nightly test
to emulate the upcoming stable compiler eyre
0.6.9 attempts to use an unstable feature anyway and fails to build
error[E0725]: the feature `rustdoc_missing_doc_code_examples` is not in the list of allowed features
Error: --> /home/runner/.cargo/registry/src/index.crates.io-6f17d22bba15001f/eyre-0.6.9/src/lib.rs:320:13
|
320 | feature(rustdoc_missing_doc_code_examples),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
member_ref
/member_mut
, change backtrace
to return an Option, add backtrace
fn to EyreContext traitanyhow
The docs on bail!()
and ensure!()
claim that these macros are equivalent to code returning Err(From::from($err))
:
https://github.com/yaahc/eyre/blob/54933ea76d12960fb4b954c81c2d288481ff9b03/src/macros.rs#L3
https://github.com/yaahc/eyre/blob/54933ea76d12960fb4b954c81c2d288481ff9b03/src/macros.rs#L66
This appears to have been inherited from anyhow
originally, although anyhow
has since updated its docs.
These macros should instead claim that they're equivalent to Err(eyre!($err))
(or possibly Err(eyre!($args...))
like anyhow
's current docs). Also, like current anyhow, it would be nice to use intra-doc links here.
Title mostly. In PR #29 #[no_std]
support was removed from the library, but not from the docs.
Due to coherence users of eyre cannot implement traits defined in their dependencies for eyre::ErrReport
. We should add feature flags to support known integrations so that users don't need to write cumbersome newtype wrappers.
Reject
trait from warpSerialization
/Deserialization
traits from serdeRight now we have nominal support for no_std
thanks to anyhow
, but its not really clear which APIs are available and which aren't when using std vs no_std.
To help with this we should use the new doc_cfg
feature to mark APIs that are and aren't available with std enabled. The tracing-subscriber repo is a good example to use as a reference for how to setup doc_cfg
.
I tried to assert_eq! two Results but alas that doesn't seem possible? Could Result support compare if the underlying types do?
(Love color-eyre!)
Hello @yaahc . What is the current status of this library?
I've found it to be fantastic to use (especially with color-eyre
) for constructing rich errors as well as getting a readable panic hook.
However, I've had to go back to anyhow and stop using this library in flax and other libraries due to the Miri/memory invalidations as well as other missing features.
It would be great to have this crate up to speed.
If you do not have the time, which is completely understandable as an open-source maintainer myself, is there any other crate which achieves a similar goal of rich errors and panic messages that you would recommend?
Best regards, Tei
In tricky build situations, such as when bootstrapping rustc or for cross-compilation, it is crucial to set the right --target
argument for rustc invocations. The build.rs script of eyre doesn't do that, and I think that's why I am now getting build failures in eyre inside a rustc bootstrap situation:
error[E0407]: method `backtrace` is not a member of trait `StdError`
--> /home/r/.cargo/registry/src/github.com-1ecc6299db9ec823/eyre-0.6.8/src/context.rs:147:5
|
147 | / fn backtrace(&self) -> Option<&Backtrace> {
148 | | self.error.backtrace()
149 | | }
| |_____^ not a member of trait `StdError`
Basically, I think eyre needs the same patch as dtolnay/anyhow#249.
(FWIW autocfg gets all this right, but it seems a lot of crates re-implement the autocfg logic -- incorrectly.)
Error 1 below appears in both stable and nightly builds.
It's slightly more impactful than just a warning. Running cargo +nightly test
, cargo test
, cargo +nightly test
in windows produces a linker error where color-spantrace tries to use eyre's usage.exe, see error 2 below. It's worked around pretty easily with cargo clean
, but it's a problem that might get worse as the monorepo effort expands!
[1]
warning: output filename collision.
The example target usage
in package eyre v0.6.8 (C:\Users\nori\dev\eyre\eyre)
has the same output filename as the example target usage
in package color-spantrace v0.2.0 (C:\Users\nori\dev\eyre\color-spantrace)
.
Colliding filename is: C:\Users\nori\dev\eyre\target\debug\examples\usage.exe
The targets should have unique names.
Consider changing their names to be unique or compiling them separately.
This may become a hard error in the future; see rust-lang/cargo#6313.
[2]
= note: LINK : fatal error LNK1104: cannot open file 'C:\Users\nori\dev\eyre\target\debug\examples\usage.exe'
error: could not compile color-spantrace
(example "usage") due to previous error
I'm compiling binaries from this project, and it's working fine on the dev machine. However, when I move the binaries to a clean linux os, running the bins returns this error:
$ cast
Error: cannot install provided ErrorHook, a hook has already been installed
Location:
cli/src/handler.rs:70:13
and the line in question is:
eyre::set_hook(Box::new(move |_| Box::new(Handler)))?;
There's also a related issue where people have ran into the same problem on Win 10.
What is causing this?
pyo3 is a direct dependency and can be upgraded to 0.20.0 painlessly.
nom is 3 major versions behind and comes via ansi-parser 0.8.0. I'll reach out to that project and ask for an upgrade =]
result of cargo test
:
warning: the following packages contain code that will be rejected by a future version of Rust: nom v4.2.3, pyo3 v0.13.2 note: to see what the problems were, use the option `--future-incompat-report`, or run `cargo report future-incompatibilities --id 1`
`
nom v4.2.3 has the following newer versions available: 5.0.0-alpha1, 5.0.0-alpha2, 5.0.0-beta1, 5.0.0-beta2, 5.0.0-beta3, 5.0.0, 5.0.1, 5.1.0, 5.1.1, 5.1.2, 5.1.3, 6.0.0-alpha1, 6.0.0-alpha2, 6.0.0-alpha3, 6.0.0-beta1, 6.0.0-beta2, 6.0.0-beta3, 6.0.0-beta4, 6.0.0-beta5, 6.0.0, 6.0.1, 6.1.0, 6.1.1, 6.1.2, 6.2.0, 6.2.1, 6.2.2, 7.0.0-alpha1, 7.0.0-alpha2, 7.0.0-alpha3, 7.0.0, 7.1.0, 7.1.1, 7.1.2, 7.1.3
pyo3 v0.13.2 has the following newer versions available: 0.14.0, 0.14.1, 0.14.2, 0.14.3, 0.14.4, 0.14.5, 0.15.0, 0.15.1, 0.15.2, 0.16.0, 0.16.1, 0.16.2, 0.16.3, 0.16.4, 0.16.5, 0.16.6, 0.17.0, 0.17.1, 0.17.2, 0.17.3, 0.18.0, 0.18.1, 0.18.2, 0.18.3, 0.19.0, 0.19.1, 0.19.2, 0.20.0
`
Hi. I started using eyre
recently, switching from anyhow
, and while it's not a big deal, it kind of bothers me every time I write eyre!(...)
. As a non-native speaker I don't even know what it means (even after quickly googling "define eyre"), I keep forgetting how to spell it and so on. I don't mind this being the crate name - because I usually write it less often, rust-analyzer can often just auto-add the import for me, and I I understand that there's a limited number of good crate names that are not taken. But the macro, I get no rust-analyzer help, have to type it myself and it looks weird and non-informative to anyone not-familiar with that crate.
anyhow!
was kind of weird already, but at least the word seemed more familiar.
Also, I'd like to point out - possibly to both authors of anyhow
and eyre
- that having these unique weird macro names makes anyhow = { crate ="eyre", ... }
be much less likely to "just work".
Is there any reason this macro couldn't be just named err!(...)
or something generic and informative like this?
Anyway, I enjoy this crate a lot, so thanks a lot for working on it!
Wrapping a source error type as the cause of an eyre::Report
is very straightforward with the wrap_err
function. But suppose I have an eyre::Result<()>
and want to convert it into a Result<(), ()>
without discarding the helpful backtrace/spantrace from eyre
? Is that even possible?
If it is, can it be documented?
First of all, thanks for the great crate. I've been waiting for a similar library for a long time. I highly like the idea of having a custom handler, because it allows more tight integration with an environment.
I'm writing the actor system and want, among other things, to provide a good experience with error handling:
eyre
allows this by providing custom handlers.
However, now I am stuck in integration with the tracing
crate (elfo's logging system is based on it now).
My goal is to print something like
... something wrong error="aa" error.source="bb" error.location="path/to/file:42" error.stacktrace=[..]
for calls like
error!(error = &some_eyre_error as &dyn Error, "something wrong");
The problem is that Report
doesn't implement Error
.
I understand that it's impossible now, so I just want to hear an opinion on how it can be solved. Maybe I miss some easy solution.
Maybe, eyre
should provide some wrapper that implements Error
and have a method to expose internally stored Report
? Of course, it can be provided by elfo, but it complicates using libraries that depend only on eyre and tracing.
Related:
Miri reports problems related to stacked borrows and strict provenance when running it over Eyre.
I also got another error previously but could not reproduce it.
Even though the stacked borrows and strict provenance memory models are experimental and what you are doing may not be treated as UB by the compiler currently, you should probably still address this, because these memory models will probably be stabilised at some point, and it clutters peoples miri output. And having Miri detect potential UB in libraries you depend on is pretty scary.
Hi and thanks for eyre! I'm not sure if this is an eyre issue or an eyre-stable issue, but is there a way to get a reference to the backtrace::Backtrace
on a Report, similar to anyhow::Error::backtrace?
It looks like the only way to convert from Box<dyn StdError + Send + Sync + 'static>
into eyre::Report
is via the eyre!()
macro. It seems odd that there's no other way, but that aside, this means of conversion does not retain the spantrace, backtrace, or any custom color-eyre
sections. It does preserve the Display
impl and the source chain. I haven't tested but I assume it preserves downcast
casting as well.
My guess here is that report.into()
throws away that data and produces the underlying boxed error (and that Report::wrap_err()
wraps the underlying error). But this is rather unfortunate.
For context, I'm trying to write library functions that take error-returning closures, need to erase the error types, and want to allow callers to use eyre::Report
on both ends of the function. I was hoping that declaring the function as using Into<Box<StdError + Send + Sync + 'static>>
would work for this, but this issue means callers will lose all of the custom eyre::Report
info.
Here's a toy sample library function:
fn library_function<E, E2>(
mut closure1: impl FnMut() -> Result<(), E>,
mut closure2: impl FnMut() -> Result<(), E2>,
) -> Result<(), Box<dyn StdError + Send + Sync + 'static>>
where
E: Into<Box<dyn StdError + Send + Sync + 'static>>,
E2: Into<Box<dyn StdError + Send + Sync + 'static>>,
{
closure1().map_err(Into::into)?;
closure2().map_err(Into::into)?;
Ok(())
}
We need to homogenize the error types, hence Box<dyn StdError + Send + Sync + 'static>
. If someone calls this like eyre!(library_function(fn_that _returns report, fn_that_returns_report))
then the resulting eyre::Report
declares its location to be the call to library_function()
and discards color-eyre
sections.
Also worth noting, the library in question doesn't know anything about eyre
, it just wants to play nicely with clients that use it.
Hi, great library, I'm enjoying it. I would like to somehow support the ?
operator in my actix-web app. The actix-web HTTP handler's support a Result<_,_>
return value so that means ?
will work, but the Err variant needs to implement their ResponseError trait: https://github.com/actix/actix-web/blob/master/actix-web/src/error/response_error.rs .
I can't implement ResponseError for eyre::Result because of the orphan rule. Any tips on how I could use eyre::Result in this scenario? And food for thought, here is how I hacked some existing code to use the stdlib Result in actix-web:
use actix_web::ResponseError;
use std::fmt::{Display, Formatter};
#[derive(Debug)]
pub struct WebError {}
impl Display for WebError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "WebError{{}}")
}
}
impl ResponseError for WebError {}
#[get("/exports/{id}/run")]
pub async fn exports_run(id: Identity, req: HttpRequest) -> Result<HttpResponse, WebError> {
let identity = id.identity().unwrap();
let pg_conn = pg_conn();
let id = req.match_info().get("id").unwrap();
let id: i32 = id.parse().map_err(|_| WebError {})?;
let job: ExportJob = export_jobs::table
.filter(export_jobs_dsl::identity.eq(&identity))
.filter(export_jobs_dsl::id.eq(id))
.first::<ExportJob>(&pg_conn)
.map_err(|_| WebError {})?;
let athena_query = sparkle_athena::StreamableAthenaResult {
athena_database: job.athena_database,
athena_view: job.athena_view,
};
let csv = execute_query(athena_query).await.map_err(|_| WebError {})?;
let mut oauth2_token = oauth_tokens_dsl::oauth2_tokens
.filter(oauth_tokens_dsl::identity.eq(&identity))
.first::<OAuth2Token>(&pg_conn)
.map_err(|_| WebError {})?;
oauth2_token
.refresh(&pg_conn)
.await
.map_err(|_| WebError {})?;
Ok(HttpResponse::Ok().body("not implemented yet"))
}
Hi,
Thanks for providing integration with PyO3!
Over in the PyO3 repo we're currently discussing accepting an anyhow
optional feature. PyO3/pyo3#1822
I am aware that you've got the pyo3
optional feature; I was wondering if for symmetry you wanted us to take ownership of the eyre
/ pyo3
integration by adding an eyre
optional feature to pyo3?
Presumably we can just copy the trait implementations you already have from this repo over to the PyO3 codebase.
I'm not sure this issue is tracking or not (or even intended), current build.rs script do not add backtrace
feature as it failed to compile since Error does not have backtrace()
API rather https://rust-lang.github.io/rfcs/3192-dyno.html.
I found this issue while comparing anyhow and found that eyre does not emit valid backtrace like anyhow. The reason is that eyre do not set backtrace feature as I explained above.
Anyhow has changed API (dtolnay/anyhow@46d3d2c).
I modified to follow the latest API and it worked at least with minimal change. Can we as eyre support such change as well?
Running cargo test
works up until thiserror 1.0.39
, but starts to fail with thiserror 1.0.40
- these two doctests fail to compile:
test src/macros.rs - macros::ensure (line 85) ... FAILED
test src/macros.rs - macros::bail (line 25) ... FAILED
This can be reproduced by running:
cargo update
cargo test
Running these two commands makes tests pass again:
cargo update --package thiserror --precise 1.0.39
cargo test
The test suite of anyhow
failed with similar errors in some recent versions, but the most recent version(s) apparently fixed this problem. It might be necessary to backport some anyhow
changes into eyre
. It seems to be related to the update to syn ^2
.
Complete error message:
---- src/macros.rs - macros::ensure (line 85) stdout ----
error: unexpected token
--> src/macros.rs:98:2
|
15 | }, 1).1,
| ^
error[E0599]: the method `eyre_kind` exists for reference `&ScienceError`, but its trait bounds were not satisfied
--> src/macros.rs:104:1
|
9 | enum ScienceError {
| -----------------
| |
| doesn't satisfy `ScienceError: Into<ErrReport>`
| doesn't satisfy `ScienceError: eyre::kind::TraitKind`
| doesn't satisfy `ScienceError: std::fmt::Display`
...
21 | ensure!(depth <= MAX_DEPTH, ScienceError::RecursionLimitExceeded);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called on `&ScienceError` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`ScienceError: Into<ErrReport>`
which is required by `ScienceError: eyre::kind::TraitKind`
`ScienceError: std::fmt::Display`
which is required by `&ScienceError: eyre::kind::AdhocKind`
`&ScienceError: Into<ErrReport>`
which is required by `&ScienceError: eyre::kind::TraitKind`
note: the traits `Into` and `std::fmt::Display` must be implemented
--> /home/deca/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/fmt/mod.rs:786:1
|
786 | pub trait Display {
| ^^^^^^^^^^^^^^^^^
|
::: /home/deca/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/convert/mod.rs:447:1
|
447 | pub trait Into<T>: Sized {
| ^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `$crate::eyre` which comes from the expansion of the macro `ensure` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0599`.
Couldn't compile the test.
---- src/macros.rs - macros::bail (line 25) stdout ----
error: unexpected token
--> src/macros.rs:38:2
|
15 | }, 1).1,
| ^
error[E0277]: the trait bound `ScienceError: std::error::Error` is not satisfied
--> src/macros.rs:43:47
|
20 | let err: &'static dyn std::error::Error = &ScienceError::RecursionLimitExceeded;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `ScienceError`
|
= note: required for the cast from `ScienceError` to the object type `dyn std::error::Error`
error[E0599]: the method `eyre_kind` exists for reference `&ScienceError`, but its trait bounds were not satisfied
--> src/macros.rs:46:5
|
9 | enum ScienceError {
| -----------------
| |
| doesn't satisfy `ScienceError: Into<ErrReport>`
| doesn't satisfy `ScienceError: eyre::kind::TraitKind`
| doesn't satisfy `ScienceError: std::fmt::Display`
...
23 | bail!(ScienceError::RecursionLimitExceeded);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called on `&ScienceError` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`ScienceError: Into<ErrReport>`
which is required by `ScienceError: eyre::kind::TraitKind`
`ScienceError: std::fmt::Display`
which is required by `&ScienceError: eyre::kind::AdhocKind`
`&ScienceError: Into<ErrReport>`
which is required by `&ScienceError: eyre::kind::TraitKind`
note: the traits `Into` and `std::fmt::Display` must be implemented
--> /home/deca/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/fmt/mod.rs:786:1
|
786 | pub trait Display {
| ^^^^^^^^^^^^^^^^^
|
::: /home/deca/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/convert/mod.rs:447:1
|
447 | pub trait Into<T>: Sized {
| ^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `$crate::eyre` which comes from the expansion of the macro `bail` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0277, E0599.
For more information about an error, try `rustc --explain E0277`.
Couldn't compile the test.
Hi,
I just started a project with tokio
, and it turned out, the current versions of eyre
and tokio
are not compatible because different versions of once_cell
are used.
Would it be possible for eyre
to upgrade to the current version of once_cell
?
based on dtolnay/anyhow#180
I'd like to move to using eyre
over anyhow
more. One downside is that eyre doesn't have the changes that make anyhow pass under miri, which means if I use eyre, much of it needs to be excluded from miri.
Also, there's at least case where the old code was UB in a way that the mutable noalias addition can exploit in theory (although in practice I suspect it would be very difficult). Fixing that requires most of the work to fix the other things, and in general
See dtolnay/anyhow#134 for the original PR to anyhow (which I wrote, for essentially the same reason that I'd like this fixed in eyre
), which talks about explicitly which patterns are bad, and gives some background.
In general the TL;DR is "doing dodgy things to &T
, &mut T
, Box<T>
1 is very bad, so you need to use raw pointers". A concrete example is that stuff like ErrorImpl<()>
pretty much needs to be held only behind a raw pointer. Instead of using an &ErrorImpl<()>
to get at the fields, you need to eitehr use core::ptr::addr_of!
/addr_of_mut!
, or convert to *const ErrorImpl<E>
which can be derefed. There are several other things like this, which are discussed in that PR.
The ergonomics of that PR are quite bad, but it got up cleaned it up significantly by introducing https://github.com/dtolnay/anyhow/blob/master/src/ptr.rs afterwards.
These basically just give NonNull more semantic meaning, and making deref
/deref_mut
unsafe (even though it probably should explain when it's safe to use it (rarely) and erm, use the correct bounds for Send/Sync ๐)
I'm willing to do the work to make this happen, but... realistically it's probably going to make the code more complex and harder to maintain2, so I figured I'd give a heads up first.
It would be useful to convert the eyre
, color-eyre
, stable-eyre
et.al. It would improve the discoverability of the different subcrates, as well as provide a single place where issues can be reported.
The current separate repositories makes it difficult for users to know where to report the errors as it may not initially be obvious if the source is in Eyre or an eyre hook implementer. It is a case of the classic "where should it go"
Merging them will improve the ease of issue creation and discovery, as well as overview.
The proposed structure will also improve ease of integration testing and examples and side-by-side development between the crates.
I like the idea of differentiating between options from errors WrapErr
intent to bring. But I still like simplicity of Option.context(..)?
. So I'd prefer to use .wrap_err
on errors and .context
on options. Actually after reading the docs I thought ContextCompat
works exactly this way, implementing .context
for options only. But it happens to bring full compatibility with anyhow.Context
, so the compiler won't guide me through changing .context
to .wrap_err
for errors. Would you consider adding something like OptionContext
which would add .context
for options only?
To summarize:
WrapErr
brings .wrap_err
for errors only, but no .context
OptionContext
brings .context
for options onlyWhat do you think?
https://docs.rs/eyre/0.6.5/eyre/macro.eyre.html
https://github.com/yaahc/eyre/blob/54933ea76d12960fb4b954c81c2d288481ff9b03/src/macros.rs#L129
This appears to have been inherited from anyhow
.
Also, when fixing this, it might be nice to add an intra-doc link to this reference.
The error returned by Mutex::lock
can't be wrapped using WrapErr::wrap_err
. Here's a MVE:
use eyre::{eyre, Result, WrapErr};
use std::sync::Mutex;
fn main() -> Result<()> {
let x = Mutex::new(0);
x.lock().wrap_err("lock")?;
// these also fail
// x.lock().map_err(|e| eyre!(e)).wrap_err("lock")?;
// x.lock().map_err(|e| eyre!(Arc::new(Mutex::new(e)))).wrap_err("lock")?;
Ok(())
}
The raised error of the above code is:
error[E0599]: the method `wrap_err` exists for enum `Result<MutexGuard<'_, {integer}>, PoisonError<MutexGuard<'_, {integer}>>>`, but its trait bounds were not satisfied
--> src/main.rs:6:14
|
6 | x.lock().wrap_err("lock")?;
| ^^^^^^^^
|
= note: the following trait bounds were not satisfied:
`PoisonError<MutexGuard<'_, {integer}>>: eyre::context::ext::StdError`
which is required by `Result<MutexGuard<'_, {integer}>, PoisonError<MutexGuard<'_, {integer}>>>: WrapErr<MutexGuard<'_, {integer}>, PoisonError<MutexGuard<'_, {integer}>>>`
`PoisonError<MutexGuard<'_, {integer}>>: Send`
which is required by `Result<MutexGuard<'_, {integer}>, PoisonError<MutexGuard<'_, {integer}>>>: WrapErr<MutexGuard<'_, {integer}>, PoisonError<MutexGuard<'_, {integer}>>>`
warning: unused import: `WrapErr`
--> src/main.rs:1:26
|
1 | use eyre::{eyre, Result, WrapErr};
| ^^^^^^^
Is there any recommended way to get around this?
Right now eyre's design essentially requires that there's a single "Handler" type that is globally used in the application. Every error Report that is created will use the globally installed constructor for this handler type to create a new handler to go with the report to store additional context and print the error report + context. This is then meant to be paired with handler().downcast::<MyExpectedHandlerType>()
when attempting to insert additional context into a Report as it propagates up the stack.
The problem is, if you are a library author who wishes to leverage eyre to hook additional functionality into error reporting you end up mandating that your users use your expected error report handler type, and if they ever install a different one all your downcasts will fail.
For a while my main plan for solving this problem has been to leverage https://github.com/mystor/object-provider to allow data to flow both ways across the dyn trait boundary without needing to downcast. This at least lets additional context be stored, so long as your users install a handler that will carry and provide your context the way you want them too, but this seems onerous and easy to forget to do.
I was looking at https://github.com/kellpossible/sentry-eyre today and trying to see what problems they were trying to solve and might run into and it dawned on me that what they might want is the ability to capture and send error report to sentry whenever they're printed, regardless of where the printing happens. The act of reporting it to a log or to a user would notify the back end.
That plus another PR that was opened today, eyre-rs/color-eyre#67, which enables composition of panic handlers, made me realize that this same approach might be very useful for EyreHandler
as well. If it was possible to take
the Box<dyn EyreHandler>
out of a report and replace it with another one we could effectively allow libraries to tap into the error handler behind a report to add additional context and functionality to reporters.
So now I need to figure out how or if this can be done. The first issue that comes to mind is losing the ability to downcast back to the original type when you wrap it, thus breaking existing integrations such as .suggestion
as provided by color-eyre
. It might be possible to work around this by doing some shenanigans in the downcast
impls in eyre
, similar to how it already supports downcasting to two alternate types for errors constructed with wrap_err
.
Another alternative is to build the composition into the trait itself by adding an inner()
method or something, essentially an equivalent to source()
on the Error
trait. Though I think I'd rather leverage the object-provider
crate for this, which lets us solve more than one problem at a time.
Yet another alternative is to allow the Report
type to store multiple handlers, which are called sequentially during reporting. This would then probably require some changes to the external interface of eyre
so that it can downcast to the correct types but it also seems like it is probably the most intuitive approach to use. I'd likely opt to deprecate the existing handler interface which I doubt anyone uses, rather than making a breaking change, since I already know from experience that that causes immediate issues to be filed in this repo, lol. Report does not match Report
is not a fun error.
The CI is failing due to the 1.42 version subset of the test matrix.
https://github.com/eyre-rs/eyre/blob/master/.github/workflows/ci.yml#L69
The reason it is failing seems to be due to thiserror
requiring the edition = 2021
. We use thiserror
in tests and documentation. I see a couple of potential directions we could go in resolving this issue:
eyre
, not attempt to run tests1.56
, the compiler version for the 2021 editionthiserror
when testing MSRVI think I lean toward the first option. I cannot anticipate any situations where we'd see breakage in runtime behavior exercised by tests across versions that we wouldn't catch due to this change. If we build in the old version and tests pass in the current version, we're almost certainly fine.
Sometimes when using eyre and printing out the error, the location sections points inside of eyre itself instead of the line at which the error occurred. What is the cause of this, and how do I avoid it?
Example error message:
Error:
0: Could not open file at "/bogus/path"
1: No such file or directory (os error 2)
Location:
/home/ryan/.cargo/registry/src/github.com-1ecc6299db9ec823/eyre-0.6.3/src/context.rs:25
Backtrace omitted.
Run with RUST_BACKTRACE=1 environment variable to display it.
Run with RUST_BACKTRACE=full to include source snippets.
Code snippet:
use eyre::{Result, WrapErr};
fn main() -> Result<()> {
color_eyre::install()?;
let args = Args::parse();
let mut reader: Box<dyn Read + Send> = if let Some(ref path) = args.path {
let reader = std::fs::File::open(path)
.wrap_err(format!("Could not open file at {:?}", path))?;
Box::new(reader)
} else {
// ....
};
//...
}
When discussing https://docs.rs/eyre/latest/eyre/index.html#context-and-option, a user remarked that a closure and macro invocation just for a static string error (as documented: opt.ok_or_else(|| eyre!("new error message"))
) seemed cumbersome.
The reasoning at the documentation's "Context
and Option
" section does make sense - WrapErr
would indicate wrapping an error, where there is (literally) None
. This issue is not asking to implement WrapErr
for Option
.
An extension trait, offering ok_or_eyre
on the Option
type does seem useful to avoid closure + macro boilerplate:
use std::fmt::{Debug, Display};
pub trait OptionExt<T> {
/// Example usage:
///
/// ```rust
/// let option: Option<()> = None;
///
/// let result = option.ok_or_eyre("static str error");
///
/// assert_eq!(result.unwrap_err().to_string(), "static str error");
/// ```
fn ok_or_eyre<M>(self, message: M) -> crate::Result<T>
where
M: Debug + Display + Send + Sync + 'static;
}
impl<T> OptionExt<T> for Option<T> {
fn ok_or_eyre<M>(self, message: M) -> crate::Result<T>
where
M: Debug + Display + Send + Sync + 'static,
{
match self {
Some(ok) => Ok(ok),
None => Err(crate::Report::msg(message)),
}
}
}
Is this something you would consider accepting as contribution? Names are of course up for bikeshedding.
Hello! Thanks for this library, I'm really enjoying it.
I would like to use an EyreHandler in a one-off fashion to write to a string, though I couldn't work out how to do this. Oops.
Would you be able to give me any tips?
Thanks,
Louis
I am trying to use eyre for unwrapping Option
s, for which I use ok_or
and &str
as the Err
-type. I figured this would work with eyre, since &str
and String
implement std::error::Error
. However, the following code does not compile:
None.ok_or("test").wrap_err("oops")
with
= note: the method `wrap_err_with` exists but the following trait bounds were not satisfied:
`&str: eyre::context::ext::StdError<_>`
which is required by `std::result::Result<usize, &str>: eyre::WrapErr<usize, &str, _>`
Do I need to implement Report
for &str
to get this working? If so, maybe it's good to add these Report
implementations for &str
and String
in the eyre crate itself?
Currently the docs suggest doing something like
let content = fs::read(path)
.wrap_err_with(|| format!("Failed to read instrs from {}", path.display()))?;
This is such a common case that the above code just becomes boilerplate. It would be nicer if it were just
let content = fs::read(path).wrap_err_with_path(path)?;
This would enable eyre Reports to be transparently converted to a js_sys::Error
. The current workaround is to convert the Report
to a string, and use that as an error, which will stringify the error chain, rather than converting it to a javascript error chain.
It might be nice to have a prelude
module that contains the macros, Report
, and WrapErr
. This way use eyre::prelude::*;
will be equivalent to
use eyre::{bail, ensure, eyre, Report, WrapErr};
as those are the items I typically want to import everywhere I use eyre (more specifically I only import the macros I use so I don't get warnings, but that the means the other macros aren't available when I want them).
Notably this should not include Result
, as taking over the bare Result
identifier without explicitly importing it would be surprising.
Right now eyre does have support for no_std
by virtue of the upstream support for no_std errors in anyhow
. However anyhow never implemented support for testing no_std
. It would be nice to update the tests to compile and pass when --no-default-features
is used, however this will require adding #[cfg(feature = "std")]
all over the test code, and to the doc tests.
Hi there, first of all, thank you very much for this project. It makes working with errors in cli implementations really pleasant and fun!
I was trying to wrap an error that comes from a library I wrote that uses thiserror:
#[derive(Debug, Error)]
pub enum MambembeKeyringError {
#[error("password not stored in the keyring yet")]
NoPasswordFound,
#[error("deserialization error")]
DeserializationError(#[from] serde_json::Error),
#[error("unknown keyring backend error")]
UnknownBackendError(#[from] KeyringError),
}
Only this should be ok but on UnknownBackendError
, that KeyringError can contain a KeyringError(OsError)
, and on windows, OsError
is windows::Error
.
I noticed the error when I tried to use ?
on a function that uses eyre::Result
and the following error showed up:
error[E0277]: `NonNull<c_void>` cannot be sent between threads safely
--> cli\src\main.rs:71:45
|
71 | mambembe_keyring::set(&services)?;
| ^ `NonNull<c_void>` cannot be sent between threads safely
|
= help: within `MambembeKeyringError`, the trait `Send` is not implemented for `NonNull<c_void>`
= note: required because it appears within the type `windows::interfaces::unknown::IUnknown`
= note: required because it appears within the type `windows::bindings::windows::win32::winrt::IRestrictedErrorInfo`
= note: required because it appears within the type `Option<windows::bindings::windows::win32::winrt::IRestrictedErrorInfo>`
= note: required because it appears within the type `windows::result::error::Error`
= note: required because it appears within the type `keyring::error::KeyringError`
= note: required because it appears within the type `MambembeKeyringError`
= note: required because of the requirements on the impl of `From<MambembeKeyringError>` for `ErrReport`
= note: required by `from`
And my first thought was to wrap it with eyre using the suggestions here:
fn wrap_keyring_error(e: MambembeKeyringError) -> Report {
// This is done because windows::Error does not allow Send
eyre!(e)
}
so I could write:
mambembe_keyring::set(&services).map_err(wrap_keyring_error)?;
but the following error returns:
error[E0599]: no method named `eyre_kind` found for reference `&MambembeKeyringError` in the current scope
--> cli\src\main.rs:177:5
|
177 | eyre!(e)
| ^^^^^^^^ method not found in `&MambembeKeyringError`
|
::: C:\Users\....\mambembe\keyring\src\lib.rs:17:1
|
17 | pub enum MambembeKeyringError {
| -----------------------------
| |
| doesn't satisfy `MambembeKeyringError: Into<ErrReport>`
| doesn't satisfy `MambembeKeyringError: Send`
| doesn't satisfy `MambembeKeyringError: Sync`
| doesn't satisfy `_: color_eyre::eyre::private::kind::TraitKind`
|
= note: the method `eyre_kind` exists but the following trait bounds were not satisfied:
`MambembeKeyringError: Into<ErrReport>`
which is required by `MambembeKeyringError: color_eyre::eyre::private::kind::TraitKind`
`MambembeKeyringError: Send`
which is required by `&MambembeKeyringError: color_eyre::eyre::private::kind::AdhocKind`
`MambembeKeyringError: Sync`
which is required by `&MambembeKeyringError: color_eyre::eyre::private::kind::AdhocKind`
`&MambembeKeyringError: Into<ErrReport>`
which is required by `&MambembeKeyringError: color_eyre::eyre::private::kind::TraitKind`
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
Do you see a solution for that?
Thanks in advance!
Nowadays Rust supports inline formatting for variables like format!("Expected {a} to be {b}")
.
This syntax works correctly in format!
, format_args!
, anyhow!
and a lot of other contexts.
However, in eyre, somewhat surprisingly, it treats the string as a literal and prints without interpolation, even though eyre itself has support for formatting when arguments are passed explicitly. It seems this stems from all macros (ensure!
, bail!
, eyre!
) having a separate branch that catches string literal with no following arguments in a special way:
macro_rules! eyre {
($msg:literal $(,)?) => { ... };
($err:expr $(,)?) => { ... };
($fmt:expr, $($arg:tt)*) => { ... };
}
Hi. After updating eyre
from 0.4.3
to 0.5.0
and color-eyre
from 0.3.4
to 0.4.1
I'm getting
the trait `std::error::Error` is not implemented for `eyre::Report<color_eyre::Handler>`
when using the ?
operator. I'm not sure if this is a bug or the breaking change implied the version bump. Thanks.
Similar e.g. to: https://doc.rust-lang.org/src/core/num/error.rs.html#32-36
IIUC, this will allow using TryInto
with eyre error type where blanket impls (like From
->TryFrom
) may return Infallible
as the error type?
RFC 2145 is on nightly now, deprecating the public_in_private lint.
https://rust-lang.github.io/rfcs/2145-type-privacy.html
See PR #113
public_in_private has been superceded by three new lints. The first two are warn-by-default and the third is allow-by-default. See the excerpt below for some details.
Lint private_interfaces is reported when a type with visibility x is used in primary interface of an item with effective visibility y and x < y. This lint is warn-by-default.
Lint private_bounds is reported when a type or trait with visibility
x is used in secondary interface of an item with effective
visibility y and x < y. This lint is warn-by-default.
Lint unnameable_types is reported when effective visibility of a
type is larger than module in which it can be named, either
directly, or through reexports, or through trivial type aliases
(type X = Y;, no generics on both sides). This lint is
allow-by-default.
Compatibility lint private_in_public is never reported and removed.
The standard library has the implementations From<'_ &str> for Box<dyn Error>
and From<String> for Box<dyn Error>
. This allows for example the following, convenient code:
fn foo() -> Result<i32, Box<dyn Error>> {
let opt: Option<i32> = None;
opt.ok_or("The Option was None");
}
assert!(foo().is_err());
Basically I use it a lot to change Option
s into Result
s in application code. When using eyre as a drop-in replacement for Result<..., Box<dyn Error>>
I have to change all of these ok_or
calls and wrap the strings with an extra macro call to eyre!
. This is inconvenient. Therefore this is a request to provide these implementations.
References:
Based on dtolnay/anyhow#97 I'd like to transition eyre
away from a generic parameter based API for error reporting customization and instead transition to using a global handler hook. This has a number of trade-offs vs the generic parameter based approach, but I think overall the global hook design the better overall set of advantages.
eyre::Report
don't need to take care to expose the Handler
type as a generic parameterOverall I think the type inference / ergonomic exposure of customization context for libraries are more valuable than the better efficiency and compile time context type checking advantages of the generic based approach. I'd also like to finalize the PR on anyhow
to potentially get these same changes built into our upstream library.
Hi,
I am porting multiple crates from anyhow to eyre, so I have code that looks something like this:
fn foo() -> Result<(), anyhow::Error> {
Ok(())
}
fn bar() -> Result<(), eyre::Report> {
let f = foo().map_err(|e| eyre::Report::new(e))?;
Ok(())
}
This, as expected, gives
error[E0277]: the trait bound `anyhow::Error: std::error::Error` is not satisfied
--> src/lib.rs:6:49
|
6 | let f = foo().map_err(|e| eyre::Report::new(e))?;
| ^ the trait `std::error::Error` is not implemented for `anyhow::Error`
|
::: /home/akshayn/.cargo/registry/src/github.com-1ecc6299db9ec823/eyre-0.6.0/src/error.rs:21:12
|
21 | E: StdError + Send + Sync + 'static,
| -------- required by this bound in `eyre::error::<impl eyre::Report>::new`
error: aborting due to previous error
Since anyhow::Error
and eyre::Report
are so similar, is there a better way to construct an eyre::Report
mid-stack than this, which is sad and throws out the context:
fn foo() -> Result<(), anyhow::Error> {
Ok(())
}
fn bar() -> Result<(), eyre::Report> {
let f = foo().map_err(|e| eyre::eyre!("{:?}", e))?;
Ok(())
}
Thanks for the help!
Hi, when you for some reason have Arc<eyre::Report>
and try to wrap it into a eyre::Report
using eyre!(...)
, it loses traces from the report (previously added with wrap_err
, etc.).
Why would you have Arc<eyre::Report>
you ask? For example moka
returns Arc
wrapped errors from some of its functions.
Hi,
I'm debugging my PR for color_eyre
at the moment. For some reason, the source code lines were not printed out.
The reason was, that I'm using a workspace and that tracing_core::metadata::Metadata contains a file path relative to the workspace, not my current working directory.
So I'm in "$workspace/color_eyre" and execute a test.
This line is then executed because filename
is "color-spantrace/tests/color_schemes.rs" โ which is relative to the workspace, not my current working directory:
// `filename` can't be found, because it's relative to the workspace
let file = match File::open(filename) {
Ok(file) => file,
// return without printing the source:
Err(ref e) if e.kind() == ErrorKind::NotFound => return Ok(()),
e @ Err(_) => e.unwrap(),
};
I believe this is only a problem for people who work on color_spantrace
, and not for end-users who install color_spantrace
via cargo (but I'm not 100% sure).
I'm reporting this in case there is an easy workaround (I can't see one), or in case this could lead to problems for end-users.
Feel free, to close this if you don't think this is a problem.
Maybe a note in the README for people who want to work on color_spantrace
would make sense?
Since eyre aims to provide a developer friendly error reporting mechanism, it would be great to not have to lose those pretty errors when crossing a FFI boundary from Rust to Python. The excellent PyO3 crate provides a way to convert from Rust errors to python exceptions via the PyErr
struct.
Because of the orphan rules, this trait can only be implemented by either PyO3 or by eyre or by a newtype that the user of the API makes. Because forcing people to make a newtype isn't in line with being developer friendly or "works out of the box", I think it makes the most sense to implement it here, gated under a feature flag like pyo3
or something so that the non-python people don't need the extra dependency.
I haven't yet explored exactly how the contextual backtrace/diagnostic info that eyre provides would actually be displayed in python, so I thought we could discuss.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.