eyre/lib.rs
1//! This library provides [`eyre::Report`][Report], a trait object based
2//! error handling type for easy idiomatic error handling and reporting in Rust
3//! applications.
4//!
5//! This crate is a fork of [`anyhow`] with support for customized
6//! error reports. For more details on customization, check out the docs on
7//! [`eyre::EyreHandler`].
8//!
9//! ## Custom Report Handlers
10//!
11//! The heart of this crate is its ability to swap out the Handler type to change
12//! what information is carried alongside errors and how the end report is
13//! formatted. This crate is meant to be used alongside companion crates that
14//! customize its behavior. Below is a list of known crates that export report
15//! handlers for eyre and short summaries of what features they provide.
16//!
17//! - [`stable-eyre`]: Switches the backtrace type from `std`'s to `backtrace-rs`'s
18//! so that it can be captured on stable. The report format is identical to
19//! `DefaultHandler`'s report format.
20//! - [`color-eyre`]: Captures a `backtrace::Backtrace` and a
21//! `tracing_error::SpanTrace`. Provides a `Section` trait for attaching warnings
22//! and suggestions to error reports. The end report is then pretty printed with
23//! the help of [`color-backtrace`], [`color-spantrace`], and `ansi_term`. Check
24//! out the README on [`color-eyre`] for details on the report format.
25//! - [`simple-eyre`]: A minimal `EyreHandler` that captures no additional
26//! information, for when you do not wish to capture `Backtrace`s with errors.
27//! - [`jane-eyre`]: A report handler crate that exists purely for the pun.
28//! Currently just re-exports `color-eyre`.
29//!
30//! ## Usage Recommendations and Stability Considerations
31//!
32//! **We recommend users do not re-export types from this library as part their
33//! own public API for libraries with external users.** The main reason for this
34//! is that it will make your library API break if we ever bump the major version
35//! number on eyre and your users upgrade the eyre version they use in their
36//! application code before you upgrade your own eyre dep version[^1].
37//!
38//! However, even beyond this API stability hazard, there are other good reasons
39//! to avoid using `eyre::Report` as your public error type.
40//!
41//! - You export an undocumented error interface that is otherwise still
42//! accessible via downcast, making it hard for users to react to specific
43//! errors while not preventing them from depending on details you didn't mean
44//! to make part of your public API.
45//! - This in turn makes the error types of all libraries you use a part of
46//! your public API as well, and makes changing any of those libraries into
47//! undetectable runtime breakage.
48//! - If many of your errors are constructed from strings, you encourage your
49//! users to use string comparison for reacting to specific errors, which is
50//! brittle and turns updating error messages into potentially undetectable
51//! runtime breakage.
52//!
53//! ## Details
54//!
55//! - Use `Result<T, eyre::Report>`, or equivalently `eyre::Result<T>`, as the
56//! return type of any fallible function.
57//!
58//! Within the function, use `?` to easily propagate any error that implements the
59//! `std::error::Error` trait.
60//!
61//! ```rust
62//! # pub trait Deserialize {}
63//! #
64//! # mod serde_json {
65//! # use super::Deserialize;
66//! # use std::io;
67//! #
68//! # pub fn from_str<T: Deserialize>(json: &str) -> io::Result<T> {
69//! # unimplemented!()
70//! # }
71//! # }
72//! #
73//! # struct ClusterMap;
74//! #
75//! # impl Deserialize for ClusterMap {}
76//! #
77//! use eyre::Result;
78//!
79//! fn get_cluster_info() -> Result<ClusterMap> {
80//! let config = std::fs::read_to_string("cluster.json")?;
81//! let map: ClusterMap = serde_json::from_str(&config)?;
82//! Ok(map)
83//! }
84//! #
85//! # fn main() {}
86//! ```
87//!
88//! - Wrap a lower level error with a new error created from a message to help the
89//! person troubleshooting understand the chain of failures that occurred. A
90//! low-level error like "No such file or directory" can be annoying to debug
91//! without more information about what higher level step the application was in
92//! the middle of.
93//!
94//! ```rust
95//! # struct It;
96//! #
97//! # impl It {
98//! # fn detach(&self) -> Result<()> {
99//! # unimplemented!()
100//! # }
101//! # }
102//! #
103//! use eyre::{WrapErr, Result};
104//!
105//! fn main() -> Result<()> {
106//! # return Ok(());
107//! #
108//! # const _: &str = stringify! {
109//! ...
110//! # };
111//! #
112//! # let it = It;
113//! # let path = "./path/to/instrs.json";
114//! #
115//! it.detach().wrap_err("Failed to detach the important thing")?;
116//!
117//! let content = std::fs::read(path)
118//! .wrap_err_with(|| format!("Failed to read instrs from {}", path))?;
119//! #
120//! # const _: &str = stringify! {
121//! ...
122//! # };
123//! #
124//! # Ok(())
125//! }
126//! ```
127//!
128//! ```console
129//! Error: Failed to read instrs from ./path/to/instrs.json
130//!
131//! Caused by:
132//! No such file or directory (os error 2)
133//! ```
134//!
135//! - Downcasting is supported and can be done by value, by shared reference, or by
136//! mutable reference as needed.
137//!
138//! ```rust
139//! # use eyre::{Report, eyre};
140//! # use std::fmt::{self, Display};
141//! # use std::task::Poll;
142//! #
143//! # #[derive(Debug)]
144//! # enum DataStoreError {
145//! # Censored(()),
146//! # }
147//! #
148//! # impl Display for DataStoreError {
149//! # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
150//! # unimplemented!()
151//! # }
152//! # }
153//! #
154//! # impl std::error::Error for DataStoreError {}
155//! #
156//! # const REDACTED_CONTENT: () = ();
157//! #
158//! # #[cfg(not(feature = "auto-install"))]
159//! # eyre::set_hook(Box::new(eyre::DefaultHandler::default_with)).unwrap();
160//! #
161//! # let error: Report = eyre!("...");
162//! # let root_cause = &error;
163//! #
164//! # let ret =
165//! // If the error was caused by redaction, then return a
166//! // tombstone instead of the content.
167//! match root_cause.downcast_ref::<DataStoreError>() {
168//! Some(DataStoreError::Censored(_)) => Ok(Poll::Ready(REDACTED_CONTENT)),
169//! None => Err(error),
170//! }
171//! # ;
172//! ```
173//!
174//! - If using the nightly channel, a backtrace is captured and printed with the
175//! error if the underlying error type does not already provide its own. In order
176//! to see backtraces, they must be enabled through the environment variables
177//! described in [`std::backtrace`]:
178//!
179//! - If you want panics and errors to both have backtraces, set
180//! `RUST_BACKTRACE=1`;
181//! - If you want only errors to have backtraces, set `RUST_LIB_BACKTRACE=1`;
182//! - If you want only panics to have backtraces, set `RUST_BACKTRACE=1` and
183//! `RUST_LIB_BACKTRACE=0`.
184//!
185//! The tracking issue for this feature is [rust-lang/rust#53487].
186//!
187//! [`std::backtrace`]: https://doc.rust-lang.org/std/backtrace/index.html#environment-variables
188//! [rust-lang/rust#53487]: https://github.com/rust-lang/rust/issues/53487
189//!
190//! - Eyre works with any error type that has an impl of `std::error::Error`,
191//! including ones defined in your crate. We do not bundle a `derive(Error)` macro
192//! but you can write the impls yourself or use a standalone macro like
193//! [thiserror].
194//!
195//! ```rust
196//! use thiserror::Error;
197//!
198//! #[derive(Error, Debug)]
199//! pub enum FormatError {
200//! #[error("Invalid header (expected {expected:?}, got {found:?})")]
201//! InvalidHeader {
202//! expected: String,
203//! found: String,
204//! },
205//! #[error("Missing attribute: {0}")]
206//! MissingAttribute(String),
207//! }
208//! ```
209//!
210//! - One-off error messages can be constructed using the `eyre!` macro, which
211//! supports string interpolation and produces an `eyre::Report`.
212//!
213//! ```rust
214//! # use eyre::{eyre, Result};
215//! #
216//! # fn demo() -> Result<()> {
217//! # let missing = "...";
218//! return Err(eyre!("Missing attribute: {}", missing));
219//! # Ok(())
220//! # }
221//! ```
222//!
223//! - On newer versions of the compiler (i.e. 1.58 and later) this macro also
224//! supports format args captures.
225//!
226//! ```rust
227//! # use eyre::{eyre, Result};
228//! #
229//! # fn demo() -> Result<()> {
230//! # let missing = "...";
231//! # #[cfg(not(eyre_no_fmt_args_capture))]
232//! return Err(eyre!("Missing attribute: {missing}"));
233//! # Ok(())
234//! # }
235//! ```
236//!
237//! ## No-std support
238//!
239//! No-std support was removed in 2020 in [commit 608a16a] due to unaddressed upstream breakages.
240//!
241//! [commit 608a16a]: https://github.com/eyre-rs/eyre/pull/29/commits/608a16aa2c2c27eca6c88001cc94c6973c18f1d5
242//!
243//! ## Comparison to failure
244//!
245//! The `eyre::Report` type works something like `failure::Error`, but unlike
246//! failure ours is built around the standard library's `std::error::Error` trait
247//! rather than a separate trait `failure::Fail`. The standard library has adopted
248//! the necessary improvements for this to be possible as part of [RFC 2504].
249//!
250//! [RFC 2504]: https://github.com/rust-lang/rfcs/blob/master/text/2504-fix-error.md
251//!
252//! ## Comparison to thiserror
253//!
254//! Use `eyre` if you don't think you'll do anything with an error other than
255//! report it. This is common in application code. Use `thiserror` if you think
256//! you need an error type that can be handled via match or reported. This is
257//! common in library crates where you don't know how your users will handle
258//! your errors.
259//!
260//! [thiserror]: https://github.com/dtolnay/thiserror
261//!
262//! ## Compatibility with `anyhow`
263//!
264//! This crate does its best to be usable as a drop in replacement of `anyhow` and
265//! vice-versa by re-exporting all of the renamed APIs with the names used in
266//! `anyhow`, though there are some differences still.
267//!
268//! #### `Context` and `Option`
269//!
270//! As part of renaming `Context` to `WrapErr` we also intentionally do not
271//! implement `WrapErr` for `Option`. This decision was made because `wrap_err`
272//! implies that you're creating a new error that saves the old error as its
273//! `source`. With `Option` there is no source error to wrap, so `wrap_err` ends up
274//! being somewhat meaningless.
275//!
276//! Instead `eyre` offers [`OptionExt::ok_or_eyre`] to yield _static_ errors from `None`,
277//! and intends for users to use the combinator functions provided by
278//! `std`, converting `Option`s to `Result`s, for _dynamic_ errors.
279//! So where you would write this with
280//! anyhow:
281//!
282//! ```rust
283//! use anyhow::Context;
284//!
285//! let opt: Option<()> = None;
286//! let result_static = opt.context("static error message");
287//! let result_dynamic = opt.with_context(|| format!("{} error message", "dynamic"));
288//! ```
289//!
290//! With `eyre` we want users to write:
291//!
292//! ```rust
293//! use eyre::{eyre, OptionExt, Result};
294//!
295//! # #[cfg(not(feature = "auto-install"))]
296//! # eyre::set_hook(Box::new(eyre::DefaultHandler::default_with)).unwrap();
297//! #
298//! let opt: Option<()> = None;
299//! let result_static: Result<()> = opt.ok_or_eyre("static error message");
300//! let result_dynamic: Result<()> = opt.ok_or_else(|| eyre!("{} error message", "dynamic"));
301//! ```
302//!
303//! **NOTE**: However, to help with porting we do provide a `ContextCompat` trait which
304//! implements `context` for options which you can import to make existing
305//! `.context` calls compile.
306//!
307//! [^1]: example and explanation of breakage <https://github.com/eyre-rs/eyre/issues/30#issuecomment-647650361>
308//!
309//! [Report]: https://docs.rs/eyre/*/eyre/struct.Report.html
310//! [`eyre::EyreHandler`]: https://docs.rs/eyre/*/eyre/trait.EyreHandler.html
311//! [`eyre::WrapErr`]: https://docs.rs/eyre/*/eyre/trait.WrapErr.html
312//! [`anyhow::Context`]: https://docs.rs/anyhow/*/anyhow/trait.Context.html
313//! [`anyhow`]: https://github.com/dtolnay/anyhow
314//! [`tracing_error::SpanTrace`]: https://docs.rs/tracing-error/*/tracing_error/struct.SpanTrace.html
315//! [`stable-eyre`]: https://github.com/eyre-rs/stable-eyre
316//! [`color-eyre`]: https://github.com/eyre-rs/color-eyre
317//! [`jane-eyre`]: https://github.com/yaahc/jane-eyre
318//! [`simple-eyre`]: https://github.com/eyre-rs/simple-eyre
319//! [`color-spantrace`]: https://github.com/eyre-rs/color-spantrace
320//! [`color-backtrace`]: https://github.com/athre0z/color-backtrace
321#![doc(html_root_url = "https://docs.rs/eyre/0.6.12")]
322#![cfg_attr(
323 nightly,
324 feature(rustdoc_missing_doc_code_examples),
325 warn(rustdoc::missing_doc_code_examples)
326)]
327#![warn(
328 missing_debug_implementations,
329 missing_docs,
330 unsafe_op_in_unsafe_fn,
331 rust_2018_idioms,
332 unreachable_pub,
333 bad_style,
334 dead_code,
335 improper_ctypes,
336 non_shorthand_field_patterns,
337 no_mangle_generic_items,
338 overflowing_literals,
339 path_statements,
340 patterns_in_fns_without_body,
341 unconditional_recursion,
342 unused,
343 unused_allocation,
344 unused_comparisons,
345 unused_parens,
346 while_true
347)]
348#![cfg_attr(generic_member_access, feature(error_generic_member_access))]
349#![cfg_attr(doc_cfg, feature(doc_cfg))]
350#![allow(
351 clippy::needless_doctest_main,
352 clippy::new_ret_no_self,
353 clippy::wrong_self_convention
354)]
355
356extern crate alloc;
357
358#[macro_use]
359mod backtrace;
360mod chain;
361mod context;
362mod error;
363mod fmt;
364mod kind;
365mod macros;
366mod option;
367mod ptr;
368mod wrapper;
369
370use crate::backtrace::Backtrace;
371use crate::error::ErrorImpl;
372use core::fmt::{Debug, Display};
373
374use std::error::Error as StdError;
375
376pub use eyre as format_err;
377/// Compatibility re-export of `eyre` for interop with `anyhow`
378pub use eyre as anyhow;
379use once_cell::sync::OnceCell;
380use ptr::OwnedPtr;
381#[doc(hidden)]
382pub use DefaultHandler as DefaultContext;
383#[doc(hidden)]
384pub use EyreHandler as EyreContext;
385#[doc(hidden)]
386pub use Report as ErrReport;
387/// Compatibility re-export of `Report` for interop with `anyhow`
388pub use Report as Error;
389/// Compatibility re-export of `WrapErr` for interop with `anyhow`
390pub use WrapErr as Context;
391
392/// The core error reporting type of the library, a wrapper around a dynamic error reporting type.
393///
394/// `Report` works a lot like `Box<dyn std::error::Error>`, but with these
395/// differences:
396///
397/// - `Report` requires that the error is `Send`, `Sync`, and `'static`.
398/// - `Report` guarantees that a backtrace is available, even if the underlying
399/// error type does not provide one.
400/// - `Report` is represented as a narrow pointer — exactly one word in
401/// size instead of two.
402///
403/// # Display representations
404///
405/// When you print an error object using "{}" or to_string(), only the outermost underlying error
406/// is printed, not any of the lower level causes. This is exactly as if you had called the Display
407/// impl of the error from which you constructed your eyre::Report.
408///
409/// ```console
410/// Failed to read instrs from ./path/to/instrs.json
411/// ```
412///
413/// To print causes as well using eyre's default formatting of causes, use the
414/// alternate selector "{:#}".
415///
416/// ```console
417/// Failed to read instrs from ./path/to/instrs.json: No such file or directory (os error 2)
418/// ```
419///
420/// The Debug format "{:?}" includes your backtrace if one was captured. Note
421/// that this is the representation you get by default if you return an error
422/// from `fn main` instead of printing it explicitly yourself.
423///
424/// ```console
425/// Error: Failed to read instrs from ./path/to/instrs.json
426///
427/// Caused by:
428/// No such file or directory (os error 2)
429///
430/// Stack backtrace:
431/// 0: <E as eyre::context::ext::StdError>::ext_report
432/// at /git/eyre/src/backtrace.rs:26
433/// 1: core::result::Result<T,E>::map_err
434/// at /git/rustc/src/libcore/result.rs:596
435/// 2: eyre::context::<impl eyre::WrapErr<T,E,H> for core::result::Result<T,E>>::wrap_err_with
436/// at /git/eyre/src/context.rs:58
437/// 3: testing::main
438/// at src/main.rs:5
439/// 4: std::rt::lang_start
440/// at /git/rustc/src/libstd/rt.rs:61
441/// 5: main
442/// 6: __libc_start_main
443/// 7: _start
444/// ```
445///
446/// To see a conventional struct-style Debug representation, use "{:#?}".
447///
448/// ```console
449/// Error {
450/// msg: "Failed to read instrs from ./path/to/instrs.json",
451/// source: Os {
452/// code: 2,
453/// kind: NotFound,
454/// message: "No such file or directory",
455/// },
456/// }
457/// ```
458///
459/// If none of the built-in representations are appropriate and you would prefer
460/// to render the error and its cause chain yourself, it can be done by defining
461/// your own [`EyreHandler`] and [`hook`] to use it.
462///
463/// [`EyreHandler`]: trait.EyreHandler.html
464/// [`hook`]: fn.set_hook.html
465#[must_use]
466pub struct Report {
467 inner: OwnedPtr<ErrorImpl<()>>,
468}
469
470type ErrorHook =
471 Box<dyn Fn(&(dyn StdError + 'static)) -> Box<dyn EyreHandler> + Sync + Send + 'static>;
472
473static HOOK: OnceCell<ErrorHook> = OnceCell::new();
474
475/// Error indicating that `set_hook` was unable to install the provided ErrorHook
476#[derive(Debug, Clone, Copy)]
477pub struct InstallError;
478
479impl core::fmt::Display for InstallError {
480 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
481 f.write_str("cannot install provided ErrorHook, a hook has already been installed")
482 }
483}
484
485impl StdError for InstallError {}
486
487/// Install the provided error hook for constructing EyreHandlers when converting
488/// Errors to Reports
489///
490/// # Details
491///
492/// To customize the format and content of error reports from `eyre` you must
493/// first define a new `EyreHandler` type to capture and store the extra context
494/// and to define the format of how to display the chain of errors and this
495/// stored context. Once this type has been defined you must also define a global
496/// hook used to construct these handlers whenever `Report`s are constructed.
497///
498/// # Examples
499///
500/// ```rust,should_panic
501/// use backtrace::Backtrace;
502/// use eyre::EyreHandler;
503/// use std::error::Error;
504/// use std::{fmt, iter};
505///
506/// fn main() -> eyre::Result<()> {
507/// // Install our custom eyre report hook for constructing our custom Handlers
508/// install().unwrap();
509///
510/// // construct a report with, hopefully, our custom handler!
511/// let mut report = eyre::eyre!("hello from custom error town!");
512///
513/// // manually set the custom msg for this report after it has been constructed
514/// if let Some(handler) = report.handler_mut().downcast_mut::<Handler>() {
515/// handler.custom_msg = Some("you're the best users, you know that right???");
516/// }
517///
518/// // print that shit!!
519/// Err(report)
520/// }
521///
522/// // define a handler that captures backtraces unless told not to
523/// fn install() -> Result<(), impl Error> {
524/// let capture_backtrace = std::env::var("RUST_BACKWARDS_TRACE")
525/// .map(|val| val != "0")
526/// .unwrap_or(true);
527///
528/// let hook = Hook { capture_backtrace };
529///
530/// eyre::set_hook(Box::new(move |e| Box::new(hook.make_handler(e))))
531/// }
532///
533/// struct Hook {
534/// capture_backtrace: bool,
535/// }
536///
537/// impl Hook {
538/// fn make_handler(&self, _error: &(dyn Error + 'static)) -> Handler {
539/// let backtrace = if self.capture_backtrace {
540/// Some(Backtrace::new())
541/// } else {
542/// None
543/// };
544///
545/// Handler {
546/// backtrace,
547/// custom_msg: None,
548/// }
549/// }
550/// }
551///
552/// struct Handler {
553/// // custom configured backtrace capture
554/// backtrace: Option<Backtrace>,
555/// // customizable message payload associated with reports
556/// custom_msg: Option<&'static str>,
557/// }
558///
559/// impl EyreHandler for Handler {
560/// fn debug(&self, error: &(dyn Error + 'static), f: &mut fmt::Formatter<'_>) -> fmt::Result {
561/// if f.alternate() {
562/// return fmt::Debug::fmt(error, f);
563/// }
564///
565/// let errors = iter::successors(Some(error), |error| (*error).source());
566///
567/// for (ind, error) in errors.enumerate() {
568/// write!(f, "\n{:>4}: {}", ind, error)?;
569/// }
570///
571/// if let Some(backtrace) = self.backtrace.as_ref() {
572/// writeln!(f, "\n\nBacktrace:\n{:?}", backtrace)?;
573/// }
574///
575/// if let Some(msg) = self.custom_msg.as_ref() {
576/// writeln!(f, "\n\n{}", msg)?;
577/// }
578///
579/// Ok(())
580/// }
581/// }
582/// ```
583pub fn set_hook(hook: ErrorHook) -> Result<(), InstallError> {
584 HOOK.set(hook).map_err(|_| InstallError)
585}
586
587#[cfg_attr(track_caller, track_caller)]
588#[cfg_attr(not(track_caller), allow(unused_mut))]
589fn capture_handler(error: &(dyn StdError + 'static)) -> Box<dyn EyreHandler> {
590 #[cfg(not(feature = "auto-install"))]
591 let hook = HOOK
592 .get()
593 .expect("a handler must always be installed if the `auto-install` feature is disabled")
594 .as_ref();
595
596 #[cfg(feature = "auto-install")]
597 let hook = HOOK
598 .get_or_init(|| Box::new(DefaultHandler::default_with))
599 .as_ref();
600
601 let mut handler = hook(error);
602
603 #[cfg(track_caller)]
604 {
605 handler.track_caller(std::panic::Location::caller())
606 }
607
608 handler
609}
610
611impl dyn EyreHandler {
612 ///
613 pub fn is<T: EyreHandler>(&self) -> bool {
614 // Get `TypeId` of the type this function is instantiated with.
615 let t = core::any::TypeId::of::<T>();
616
617 // Get `TypeId` of the type in the trait object (`self`).
618 let concrete = self.type_id();
619
620 // Compare both `TypeId`s on equality.
621 t == concrete
622 }
623
624 ///
625 pub fn downcast_ref<T: EyreHandler>(&self) -> Option<&T> {
626 if self.is::<T>() {
627 unsafe { Some(&*(self as *const dyn EyreHandler as *const T)) }
628 } else {
629 None
630 }
631 }
632
633 ///
634 pub fn downcast_mut<T: EyreHandler>(&mut self) -> Option<&mut T> {
635 if self.is::<T>() {
636 unsafe { Some(&mut *(self as *mut dyn EyreHandler as *mut T)) }
637 } else {
638 None
639 }
640 }
641}
642
643/// Error Report Handler trait for customizing `eyre::Report`
644pub trait EyreHandler: core::any::Any + Send + Sync {
645 /// Define the report format
646 ///
647 /// Used to override the report format of `eyre::Report`
648 ///
649 /// # Example
650 ///
651 /// ```rust
652 /// use backtrace::Backtrace;
653 /// use eyre::EyreHandler;
654 /// use eyre::Chain;
655 /// use std::error::Error;
656 /// use indenter::indented;
657 ///
658 /// pub struct Handler {
659 /// backtrace: Backtrace,
660 /// }
661 ///
662 /// impl EyreHandler for Handler {
663 /// fn debug(
664 /// &self,
665 /// error: &(dyn Error + 'static),
666 /// f: &mut core::fmt::Formatter<'_>,
667 /// ) -> core::fmt::Result {
668 /// use core::fmt::Write as _;
669 ///
670 /// if f.alternate() {
671 /// return core::fmt::Debug::fmt(error, f);
672 /// }
673 ///
674 /// write!(f, "{}", error)?;
675 ///
676 /// if let Some(cause) = error.source() {
677 /// write!(f, "\n\nCaused by:")?;
678 /// let multiple = cause.source().is_some();
679 ///
680 /// for (n, error) in Chain::new(cause).enumerate() {
681 /// writeln!(f)?;
682 /// if multiple {
683 /// write!(indented(f).ind(n), "{}", error)?;
684 /// } else {
685 /// write!(indented(f), "{}", error)?;
686 /// }
687 /// }
688 /// }
689 ///
690 /// let backtrace = &self.backtrace;
691 /// write!(f, "\n\nStack backtrace:\n{:?}", backtrace)?;
692 ///
693 /// Ok(())
694 /// }
695 /// }
696 /// ```
697 fn debug(
698 &self,
699 error: &(dyn StdError + 'static),
700 f: &mut core::fmt::Formatter<'_>,
701 ) -> core::fmt::Result;
702
703 /// Override for the `Display` format
704 fn display(
705 &self,
706 error: &(dyn StdError + 'static),
707 f: &mut core::fmt::Formatter<'_>,
708 ) -> core::fmt::Result {
709 write!(f, "{}", error)?;
710
711 if f.alternate() {
712 for cause in crate::chain::Chain::new(error).skip(1) {
713 write!(f, ": {}", cause)?;
714 }
715 }
716
717 Result::Ok(())
718 }
719
720 /// Store the location of the caller who constructed this error report
721 #[allow(unused_variables)]
722 fn track_caller(&mut self, location: &'static std::panic::Location<'static>) {}
723}
724
725/// The default provided error report handler for `eyre::Report`.
726///
727/// On nightly this supports conditionally capturing a `std::backtrace::Backtrace` if the source
728/// error did not already capture one.
729#[allow(dead_code)]
730pub struct DefaultHandler {
731 backtrace: Option<Backtrace>,
732 #[cfg(track_caller)]
733 location: Option<&'static std::panic::Location<'static>>,
734}
735
736impl DefaultHandler {
737 /// Manual hook which constructs `DefaultHandler`s.
738 ///
739 /// # Details
740 ///
741 /// When supplied to the `set_hook` function, `default_with` will cause `eyre::Report` to use
742 /// `DefaultHandler` as the error report handler.
743 ///
744 /// If the `auto-install` feature is enabled, and a user-provided hook for constructing
745 /// `EyreHandlers` was not installed using `set_hook`, `DefaultHandler::default_with`
746 /// is automatically installed as the hook.
747 ///
748 /// # Example
749 ///
750 /// ```rust,should_panic
751 /// use eyre::{DefaultHandler, eyre, InstallError, Result, set_hook};
752 ///
753 /// fn main() -> Result<()> {
754 /// install_default().expect("default handler inexplicably already installed");
755 /// Err(eyre!("hello from default error city!"))
756 /// }
757 ///
758 /// fn install_default() -> Result<(), InstallError> {
759 /// set_hook(Box::new(DefaultHandler::default_with))
760 /// }
761 ///
762 /// ```
763 #[allow(unused_variables)]
764 #[cfg_attr(not(feature = "auto-install"), allow(dead_code))]
765 pub fn default_with(error: &(dyn StdError + 'static)) -> Box<dyn EyreHandler> {
766 // Capture the backtrace if the source error did not already capture one
767 let backtrace = backtrace_if_absent!(error);
768
769 Box::new(Self {
770 backtrace,
771 #[cfg(track_caller)]
772 location: None,
773 })
774 }
775}
776
777impl core::fmt::Debug for DefaultHandler {
778 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
779 f.debug_struct("DefaultHandler")
780 .field(
781 "backtrace",
782 match &self.backtrace {
783 Some(_) => &"Some(Backtrace { ... })",
784 None => &"None",
785 },
786 )
787 .finish()
788 }
789}
790
791impl EyreHandler for DefaultHandler {
792 fn debug(
793 &self,
794 error: &(dyn StdError + 'static),
795 f: &mut core::fmt::Formatter<'_>,
796 ) -> core::fmt::Result {
797 use core::fmt::Write as _;
798
799 if f.alternate() {
800 return core::fmt::Debug::fmt(error, f);
801 }
802
803 write!(f, "{}", error)?;
804
805 if let Some(cause) = error.source() {
806 write!(f, "\n\nCaused by:")?;
807 let multiple = cause.source().is_some();
808 for (n, error) in crate::chain::Chain::new(cause).enumerate() {
809 writeln!(f)?;
810 if multiple {
811 write!(indenter::indented(f).ind(n), "{}", error)?;
812 } else {
813 write!(indenter::indented(f), "{}", error)?;
814 }
815 }
816 }
817
818 #[cfg(all(track_caller, feature = "track-caller"))]
819 {
820 if let Some(location) = self.location {
821 write!(f, "\n\nLocation:\n")?;
822 write!(indenter::indented(f), "{}", location)?;
823 }
824 }
825
826 use std::backtrace::BacktraceStatus;
827
828 let backtrace = self.backtrace.as_ref();
829
830 #[cfg(generic_member_access)]
831 // The backtrace can be stored either in the handler instance, or the error itself.
832 // If the source error has a backtrace, the handler should not capture one
833 let backtrace = backtrace.or_else(|| {
834 Some(std::error::request_ref::<Backtrace>(error).expect("backtrace capture failed"))
835 });
836
837 if let Some(backtrace) = backtrace {
838 if BacktraceStatus::Captured == backtrace.status() {
839 write!(f, "\n\nStack backtrace:\n{}", backtrace)?;
840 }
841 }
842
843 Result::Ok(())
844 }
845
846 #[cfg(track_caller)]
847 fn track_caller(&mut self, location: &'static std::panic::Location<'static>) {
848 self.location = Some(location);
849 }
850}
851
852/// Iterator of a chain of source errors.
853///
854/// This type is the iterator returned by [`Report::chain`].
855///
856/// # Example
857///
858/// ```
859/// use eyre::Report;
860/// use std::io;
861///
862/// pub fn underlying_io_error_kind(error: &Report) -> Option<io::ErrorKind> {
863/// for cause in error.chain() {
864/// if let Some(io_error) = cause.downcast_ref::<io::Error>() {
865/// return Some(io_error.kind());
866/// }
867/// }
868/// None
869/// }
870/// ```
871#[derive(Clone)]
872#[allow(missing_debug_implementations)]
873pub struct Chain<'a> {
874 state: crate::chain::ChainState<'a>,
875}
876
877/// type alias for `Result<T, Report>`
878///
879/// This is a reasonable return type to use throughout your application but also for `fn main`; if
880/// you do, failures will be printed along with a backtrace if one was captured.
881///
882/// `eyre::Result` may be used with one *or* two type parameters.
883///
884/// ```rust
885/// use eyre::Result;
886///
887/// # const IGNORE: &str = stringify! {
888/// fn demo1() -> Result<T> {...}
889/// // ^ equivalent to std::result::Result<T, eyre::Report>
890///
891/// fn demo2() -> Result<T, OtherError> {...}
892/// // ^ equivalent to std::result::Result<T, OtherError>
893/// # };
894/// ```
895///
896/// # Example
897///
898/// ```
899/// # pub trait Deserialize {}
900/// #
901/// # mod serde_json {
902/// # use super::Deserialize;
903/// # use std::io;
904/// #
905/// # pub fn from_str<T: Deserialize>(json: &str) -> io::Result<T> {
906/// # unimplemented!()
907/// # }
908/// # }
909/// #
910/// # #[derive(Debug)]
911/// # struct ClusterMap;
912/// #
913/// # impl Deserialize for ClusterMap {}
914/// #
915/// use eyre::Result;
916///
917/// fn main() -> Result<()> {
918/// # return Ok(());
919/// let config = std::fs::read_to_string("cluster.json")?;
920/// let map: ClusterMap = serde_json::from_str(&config)?;
921/// println!("cluster info: {:#?}", map);
922/// Ok(())
923/// }
924/// ```
925pub type Result<T = (), E = Report> = core::result::Result<T, E>;
926
927/// Provides the `wrap_err` method for `Result`.
928///
929/// This trait is sealed and cannot be implemented for types outside of
930/// `eyre`.
931///
932/// # Example
933///
934/// ```
935/// use eyre::{WrapErr, Result};
936/// use std::fs;
937/// use std::path::PathBuf;
938///
939/// pub struct ImportantThing {
940/// path: PathBuf,
941/// }
942///
943/// impl ImportantThing {
944/// # const IGNORE: &'static str = stringify! {
945/// pub fn detach(&mut self) -> Result<()> {...}
946/// # };
947/// # fn detach(&mut self) -> Result<()> {
948/// # unimplemented!()
949/// # }
950/// }
951///
952/// pub fn do_it(mut it: ImportantThing) -> Result<Vec<u8>> {
953/// it.detach().wrap_err("Failed to detach the important thing")?;
954///
955/// let path = &it.path;
956/// let content = fs::read(path)
957/// .wrap_err_with(|| format!("Failed to read instrs from {}", path.display()))?;
958///
959/// Ok(content)
960/// }
961/// ```
962///
963/// When printed, the outermost error would be printed first and the lower
964/// level underlying causes would be enumerated below.
965///
966/// ```console
967/// Error: Failed to read instrs from ./path/to/instrs.json
968///
969/// Caused by:
970/// No such file or directory (os error 2)
971/// ```
972///
973/// # Wrapping Types That Don't impl `Error` (e.g. `&str` and `Box<dyn Error>`)
974///
975/// Due to restrictions for coherence `Report` cannot impl `From` for types that don't impl
976/// `Error`. Attempts to do so will give "this type might implement Error in the future" as an
977/// error. As such, `wrap_err`, which uses `From` under the hood, cannot be used to wrap these
978/// types. Instead we encourage you to use the combinators provided for `Result` in `std`/`core`.
979///
980/// For example, instead of this:
981///
982/// ```rust,compile_fail
983/// use std::error::Error;
984/// use eyre::{WrapErr, Report};
985///
986/// fn wrap_example(err: Result<(), Box<dyn Error + Send + Sync + 'static>>) -> Result<(), Report> {
987/// err.wrap_err("saw a downstream error")
988/// }
989/// ```
990///
991/// We encourage you to write this:
992///
993/// ```rust
994/// use std::error::Error;
995/// use eyre::{WrapErr, Report, eyre};
996///
997/// fn wrap_example(err: Result<(), Box<dyn Error + Send + Sync + 'static>>) -> Result<(), Report> {
998/// err.map_err(|e| eyre!(e)).wrap_err("saw a downstream error")
999/// }
1000/// ```
1001///
1002/// # Effect on downcasting
1003///
1004/// After attaching a message of type `D` onto an error of type `E`, the resulting
1005/// `eyre::Report` may be downcast to `D` **or** to `E`.
1006///
1007/// That is, in codebases that rely on downcasting, Eyre's wrap_err supports
1008/// both of the following use cases:
1009///
1010/// - **Attaching messages whose type is insignificant onto errors whose type
1011/// is used in downcasts.**
1012///
1013/// In other error libraries whose wrap_err is not designed this way, it can
1014/// be risky to introduce messages to existing code because new message might
1015/// break existing working downcasts. In Eyre, any downcast that worked
1016/// before adding the message will continue to work after you add a message, so
1017/// you should freely wrap errors wherever it would be helpful.
1018///
1019/// ```
1020/// # use eyre::bail;
1021/// # use thiserror::Error;
1022/// #
1023/// # #[derive(Error, Debug)]
1024/// # #[error("???")]
1025/// # struct SuspiciousError;
1026/// #
1027/// # fn helper() -> Result<()> {
1028/// # bail!(SuspiciousError);
1029/// # }
1030/// #
1031/// use eyre::{WrapErr, Result};
1032///
1033/// fn do_it() -> Result<()> {
1034/// helper().wrap_err("Failed to complete the work")?;
1035/// # const IGNORE: &str = stringify! {
1036/// ...
1037/// # };
1038/// # unreachable!()
1039/// }
1040///
1041/// fn main() {
1042/// # #[cfg(not(feature = "auto-install"))]
1043/// # eyre::set_hook(Box::new(eyre::DefaultHandler::default_with)).unwrap();
1044/// let err = do_it().unwrap_err();
1045/// if let Some(e) = err.downcast_ref::<SuspiciousError>() {
1046/// // If helper() returned SuspiciousError, this downcast will
1047/// // correctly succeed even with the message in between.
1048/// # return;
1049/// }
1050/// # panic!("expected downcast to succeed");
1051/// }
1052/// ```
1053///
1054/// - **Attaching message whose type is used in downcasts onto errors whose
1055/// type is insignificant.**
1056///
1057/// Some codebases prefer to use machine-readable messages to categorize
1058/// lower level errors in a way that will be actionable to higher levels of
1059/// the application.
1060///
1061/// ```
1062/// # use eyre::bail;
1063/// # use thiserror::Error;
1064/// #
1065/// # #[derive(Error, Debug)]
1066/// # #[error("???")]
1067/// # struct HelperFailed;
1068/// #
1069/// # fn helper() -> Result<()> {
1070/// # bail!("no such file or directory");
1071/// # }
1072/// #
1073/// use eyre::{WrapErr, Result};
1074///
1075/// fn do_it() -> Result<()> {
1076/// helper().wrap_err(HelperFailed)?;
1077/// # const IGNORE: &str = stringify! {
1078/// ...
1079/// # };
1080/// # unreachable!()
1081/// }
1082///
1083/// fn main() {
1084/// # #[cfg(not(feature = "auto-install"))]
1085/// # eyre::set_hook(Box::new(eyre::DefaultHandler::default_with)).unwrap();
1086/// let err = do_it().unwrap_err();
1087/// if let Some(e) = err.downcast_ref::<HelperFailed>() {
1088/// // If helper failed, this downcast will succeed because
1089/// // HelperFailed is the message that has been attached to
1090/// // that error.
1091/// # return;
1092/// }
1093/// # panic!("expected downcast to succeed");
1094/// }
1095/// ```
1096///
1097/// # `wrap_err` vs `wrap_err_with`
1098///
1099/// `wrap_err` incurs a runtime cost even in the non-error case because it requires eagerly
1100/// constructing the error object. `wrap_err_with` avoids this cost through lazy evaluation. This
1101/// cost is proportional to the cost of the currently installed [`EyreHandler`]'s creation step.
1102/// `wrap_err` is useful in cases where an constructed error object already exists.
1103pub trait WrapErr<T, E>: context::private::Sealed {
1104 /// Wrap the error value with a new adhoc error
1105 #[cfg_attr(track_caller, track_caller)]
1106 fn wrap_err<D>(self, msg: D) -> Result<T, Report>
1107 where
1108 D: Display + Send + Sync + 'static;
1109
1110 /// Wrap the error value with a new adhoc error that is evaluated lazily
1111 /// only once an error does occur.
1112 #[cfg_attr(track_caller, track_caller)]
1113 fn wrap_err_with<D, F>(self, f: F) -> Result<T, Report>
1114 where
1115 D: Display + Send + Sync + 'static,
1116 F: FnOnce() -> D;
1117
1118 /// Compatibility re-export of wrap_err for interop with `anyhow`
1119 #[cfg_attr(track_caller, track_caller)]
1120 fn context<D>(self, msg: D) -> Result<T, Report>
1121 where
1122 D: Display + Send + Sync + 'static;
1123
1124 /// Compatibility re-export of wrap_err_with for interop with `anyhow`
1125 #[cfg_attr(track_caller, track_caller)]
1126 fn with_context<D, F>(self, f: F) -> Result<T, Report>
1127 where
1128 D: Display + Send + Sync + 'static,
1129 F: FnOnce() -> D;
1130}
1131
1132/// Provides the [`ok_or_eyre`][OptionExt::ok_or_eyre] method for [`Option`].
1133///
1134/// This trait is sealed and cannot be implemented for types outside of
1135/// `eyre`.
1136///
1137/// # Example
1138///
1139/// ```
1140/// # #[cfg(not(feature = "auto-install"))]
1141/// # eyre::set_hook(Box::new(eyre::DefaultHandler::default_with)).unwrap();
1142/// use eyre::OptionExt;
1143///
1144/// let option: Option<()> = None;
1145///
1146/// let result = option.ok_or_eyre("static str error");
1147///
1148/// assert_eq!(result.unwrap_err().to_string(), "static str error");
1149/// ```
1150///
1151/// # `ok_or_eyre` vs `ok_or_else`
1152///
1153/// If string interpolation is required for the generated [report][Report],
1154/// use [`ok_or_else`][Option::ok_or_else] instead,
1155/// invoking [`eyre!`] to perform string interpolation:
1156///
1157/// ```
1158/// # #[cfg(not(feature = "auto-install"))]
1159/// # eyre::set_hook(Box::new(eyre::DefaultHandler::default_with)).unwrap();
1160/// use eyre::eyre;
1161///
1162/// let option: Option<()> = None;
1163///
1164/// let result = option.ok_or_else(|| eyre!("{} error", "dynamic"));
1165///
1166/// assert_eq!(result.unwrap_err().to_string(), "dynamic error");
1167/// ```
1168///
1169/// `ok_or_eyre` incurs no runtime cost, as the error object
1170/// is constructed from the provided static argument
1171/// only in the `None` case.
1172pub trait OptionExt<T>: context::private::Sealed {
1173 /// Transform the [`Option<T>`] into a [`Result<T, E>`],
1174 /// mapping [`Some(v)`][Option::Some] to [`Ok(v)`][Result::Ok]
1175 /// and [`None`] to [`Report`].
1176 ///
1177 /// `ok_or_eyre` allows for eyre [`Report`] error objects
1178 /// to be lazily created from static messages in the `None` case.
1179 ///
1180 /// For dynamic error messages, use [`ok_or_else`][Option::ok_or_else],
1181 /// invoking [`eyre!`] in the closure to perform string interpolation.
1182 fn ok_or_eyre<M>(self, message: M) -> crate::Result<T>
1183 where
1184 M: Debug + Display + Send + Sync + 'static;
1185}
1186
1187/// Provides the `context` method for `Option` when porting from `anyhow`
1188///
1189/// This trait is sealed and cannot be implemented for types outside of
1190/// `eyre`.
1191///
1192/// ## Why Doesn't `Eyre` impl `WrapErr` for `Option`?
1193///
1194/// `eyre` doesn't impl `WrapErr` for `Option` because `wrap_err` implies that you're creating a
1195/// new error that saves the previous error as its `source`. Calling `wrap_err` on an `Option` is
1196/// meaningless because there is no source error. `anyhow` avoids this issue by using a different
1197/// mental model where you're adding "context" to an error, though this not a mental model for
1198/// error handling that `eyre` agrees with.
1199///
1200/// Instead, `eyre` encourages users to think of each error as distinct, where the previous error
1201/// is the context being saved by the new error, which is backwards compared to anyhow's model. In
1202/// this model you're encouraged to use combinators provided by `std` for `Option` to convert an
1203/// option to a `Result`
1204///
1205/// # Example
1206///
1207/// Instead of:
1208///
1209/// ```rust
1210/// use eyre::ContextCompat;
1211///
1212/// fn get_thing(mut things: impl Iterator<Item = u32>) -> eyre::Result<u32> {
1213/// things
1214/// .find(|&thing| thing == 42)
1215/// .context("the thing wasnt in the list")
1216/// }
1217/// ```
1218///
1219/// We encourage you to use this:
1220///
1221/// ```rust
1222/// use eyre::eyre;
1223///
1224/// fn get_thing(mut things: impl Iterator<Item = u32>) -> eyre::Result<u32> {
1225/// things
1226/// .find(|&thing| thing == 42)
1227/// .ok_or_else(|| eyre!("the thing wasnt in the list"))
1228/// }
1229/// ```
1230pub trait ContextCompat<T>: context::private::Sealed {
1231 /// Compatibility version of `wrap_err` for creating new errors with new source on `Option`
1232 /// when porting from `anyhow`
1233 #[cfg_attr(track_caller, track_caller)]
1234 fn context<D>(self, msg: D) -> Result<T, Report>
1235 where
1236 D: Display + Send + Sync + 'static;
1237
1238 /// Compatibility version of `wrap_err_with` for creating new errors with new source on `Option`
1239 /// when porting from `anyhow`
1240 #[cfg_attr(track_caller, track_caller)]
1241 fn with_context<D, F>(self, f: F) -> Result<T, Report>
1242 where
1243 D: Display + Send + Sync + 'static,
1244 F: FnOnce() -> D;
1245
1246 /// Compatibility re-export of `context` for porting from `anyhow` to `eyre`
1247 #[cfg_attr(track_caller, track_caller)]
1248 fn wrap_err<D>(self, msg: D) -> Result<T, Report>
1249 where
1250 D: Display + Send + Sync + 'static;
1251
1252 /// Compatibility re-export of `with_context` for porting from `anyhow` to `eyre`
1253 #[cfg_attr(track_caller, track_caller)]
1254 fn wrap_err_with<D, F>(self, f: F) -> Result<T, Report>
1255 where
1256 D: Display + Send + Sync + 'static,
1257 F: FnOnce() -> D;
1258}
1259
1260/// Equivalent to Ok::<_, eyre::Error>(value).
1261///
1262/// This simplifies creation of an eyre::Result in places where type inference
1263/// cannot deduce the `E` type of the result — without needing to write
1264/// `Ok::<_, eyre::Error>(value)`.
1265///
1266/// One might think that `eyre::Result::Ok(value)` would work in such cases
1267/// but it does not.
1268///
1269/// ```console
1270/// error[E0282]: type annotations needed for `std::result::Result<i32, E>`
1271/// --> src/main.rs:11:13
1272/// |
1273/// 11 | let _ = eyre::Result::Ok(1);
1274/// | - ^^^^^^^^^^^^^^^^ cannot infer type for type parameter `E` declared on the enum `Result`
1275/// | |
1276/// | consider giving this pattern the explicit type `std::result::Result<i32, E>`, where the type parameter `E` is specified
1277/// ```
1278#[allow(non_snake_case)]
1279pub fn Ok<T>(t: T) -> Result<T> {
1280 Result::Ok(t)
1281}
1282
1283// Not public API. Referenced by macro-generated code.
1284#[doc(hidden)]
1285pub mod private {
1286 use crate::Report;
1287 use alloc::fmt;
1288 use core::fmt::{Arguments, Debug, Display};
1289
1290 pub use alloc::format;
1291 pub use core::format_args;
1292 pub use core::result::Result::Err;
1293
1294 #[doc(hidden)]
1295 pub mod kind {
1296 pub use crate::kind::{AdhocKind, TraitKind};
1297
1298 pub use crate::kind::BoxedKind;
1299 }
1300
1301 #[cfg_attr(track_caller, track_caller)]
1302 pub fn new_adhoc<M>(message: M) -> Report
1303 where
1304 M: Display + Debug + Send + Sync + 'static,
1305 {
1306 Report::from_adhoc(message)
1307 }
1308
1309 #[doc(hidden)]
1310 #[cold]
1311 #[cfg_attr(track_caller, track_caller)]
1312 pub fn format_err(args: Arguments<'_>) -> Report {
1313 #[cfg(eyre_no_fmt_arguments_as_str)]
1314 let fmt_arguments_as_str: Option<&str> = None;
1315 #[cfg(not(eyre_no_fmt_arguments_as_str))]
1316 let fmt_arguments_as_str = args.as_str();
1317
1318 if let Some(message) = fmt_arguments_as_str {
1319 // eyre!("literal"), can downcast to &'static str
1320 Report::msg(message)
1321 } else {
1322 // eyre!("interpolate {var}"), can downcast to String
1323 Report::msg(fmt::format(args))
1324 }
1325 }
1326}