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 a support for customized
6//! error reports. For more details on customization checkout the docs on
7//! [`eyre::EyreHandler`].
8//!
9//! ## Custom Report Handlers
10//!
11//! The heart of this crate is it's 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 it's 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 an
47//! undetectable runtime breakage.
48//! - If many of your errors are constructed from strings you encourage your
49//! users to use string comparision for reacting to specific errors which is
50//! brittle and turns updating error messages into a 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 what the chain of failures that occured. 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 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//! - On newer versions of the compiler (e.g. 1.58 and later) this macro also
223//! supports format args captures.
224//!
225//! ```rust
226//! # use eyre::{eyre, Result};
227//! #
228//! # fn demo() -> Result<()> {
229//! # let missing = "...";
230//! # #[cfg(not(eyre_no_fmt_args_capture))]
231//! return Err(eyre!("Missing attribute: {missing}"));
232//! # Ok(())
233//! # }
234//! ```
235//!
236//! ## No-std support
237//!
238//! **NOTE**: tests are currently broken for `no_std` so I cannot guarantee that
239//! everything works still. I'm waiting for upstream fixes to be merged rather than
240//! fixing them myself, so bear with me.
241//!
242//! In no_std mode, the same API is almost all available and works the same way. To
243//! depend on Eyre in no_std mode, disable our default enabled "std" feature in
244//! Cargo.toml. A global allocator is required.
245//!
246//! ```toml
247//! [dependencies]
248//! eyre = { version = "0.6", default-features = false }
249//! ```
250//!
251//! Since the `?`-based error conversions would normally rely on the
252//! `std::error::Error` trait which is only available through std, no_std mode will
253//! require an explicit `.map_err(Report::msg)` when working with a non-Eyre error
254//! type inside a function that returns Eyre's error type.
255//!
256//! ## Comparison to failure
257//!
258//! The `eyre::Report` type works something like `failure::Error`, but unlike
259//! failure ours is built around the standard library's `std::error::Error` trait
260//! rather than a separate trait `failure::Fail`. The standard library has adopted
261//! the necessary improvements for this to be possible as part of [RFC 2504].
262//!
263//! [RFC 2504]: https://github.com/rust-lang/rfcs/blob/master/text/2504-fix-error.md
264//!
265//! ## Comparison to thiserror
266//!
267//! Use `eyre` if you don't think you'll do anything with an error other than
268//! report it. This is common in application code. Use `thiserror` if you think
269//! you need an error type that can be handled via match or reported. This is
270//! common in library crates where you don't know how your users will handle
271//! your errors.
272//!
273//! [thiserror]: https://github.com/dtolnay/thiserror
274//!
275//! ## Compatibility with `anyhow`
276//!
277//! This crate does its best to be usable as a drop in replacement of `anyhow` and
278//! vice-versa by `re-exporting` all of the renamed APIs with the names used in
279//! `anyhow`, though there are some differences still.
280//!
281//! #### `Context` and `Option`
282//!
283//! As part of renaming `Context` to `WrapErr` we also intentionally do not
284//! implement `WrapErr` for `Option`. This decision was made because `wrap_err`
285//! implies that you're creating a new error that saves the old error as its
286//! `source`. With `Option` there is no source error to wrap, so `wrap_err` ends up
287//! being somewhat meaningless.
288//!
289//! Instead `eyre` intends for users to use the combinator functions provided by
290//! `std` for converting `Option`s to `Result`s. So where you would write this with
291//! anyhow:
292//!
293//! ```rust
294//! use anyhow::Context;
295//!
296//! let opt: Option<()> = None;
297//! let result = opt.context("new error message");
298//! ```
299//!
300//! With `eyre` we want users to write:
301//!
302//! ```rust
303//! use eyre::{eyre, Result};
304//!
305//! # #[cfg(not(feature = "auto-install"))]
306//! # eyre::set_hook(Box::new(eyre::DefaultHandler::default_with)).unwrap();
307//! #
308//! let opt: Option<()> = None;
309//! let result: Result<()> = opt.ok_or_else(|| eyre!("new error message"));
310//! ```
311//!
312//! **NOTE**: However, to help with porting we do provide a `ContextCompat` trait which
313//! implements `context` for options which you can import to make existing
314//! `.context` calls compile.
315//!
316//! [^1]: example and explanation of breakage https://github.com/yaahc/eyre/issues/30#issuecomment-647650361
317//!
318//! [Report]: https://docs.rs/eyre/*/eyre/struct.Report.html
319//! [`eyre::EyreHandler`]: https://docs.rs/eyre/*/eyre/trait.EyreHandler.html
320//! [`eyre::WrapErr`]: https://docs.rs/eyre/*/eyre/trait.WrapErr.html
321//! [`anyhow::Context`]: https://docs.rs/anyhow/*/anyhow/trait.Context.html
322//! [`anyhow`]: https://github.com/dtolnay/anyhow
323//! [`tracing_error::SpanTrace`]: https://docs.rs/tracing-error/*/tracing_error/struct.SpanTrace.html
324//! [`stable-eyre`]: https://github.com/yaahc/stable-eyre
325//! [`color-eyre`]: https://github.com/yaahc/color-eyre
326//! [`jane-eyre`]: https://github.com/yaahc/jane-eyre
327//! [`simple-eyre`]: https://github.com/yaahc/simple-eyre
328//! [`color-spantrace`]: https://github.com/yaahc/color-spantrace
329//! [`color-backtrace`]: https://github.com/athre0z/color-backtrace
330#![doc(html_root_url = "https://docs.rs/eyre/0.6.8")]
331#![warn(
332 missing_debug_implementations,
333 missing_docs,
334 missing_doc_code_examples,
335 rust_2018_idioms,
336 unreachable_pub,
337 bad_style,
338 const_err,
339 dead_code,
340 improper_ctypes,
341 non_shorthand_field_patterns,
342 no_mangle_generic_items,
343 overflowing_literals,
344 path_statements,
345 patterns_in_fns_without_body,
346 private_in_public,
347 unconditional_recursion,
348 unused,
349 unused_allocation,
350 unused_comparisons,
351 unused_parens,
352 while_true
353)]
354#![cfg_attr(backtrace, feature(backtrace))]
355#![cfg_attr(doc_cfg, feature(doc_cfg))]
356#![allow(
357 clippy::needless_doctest_main,
358 clippy::new_ret_no_self,
359 clippy::wrong_self_convention
360)]
361
362extern crate alloc;
363
364#[macro_use]
365mod backtrace;
366mod chain;
367mod context;
368mod error;
369mod fmt;
370mod kind;
371mod macros;
372mod wrapper;
373
374use crate::backtrace::Backtrace;
375use crate::error::ErrorImpl;
376use core::fmt::Display;
377use core::mem::ManuallyDrop;
378
379use std::error::Error as StdError;
380
381pub use eyre as format_err;
382/// Compatibility re-export of `eyre` for interopt with `anyhow`
383pub use eyre as anyhow;
384use once_cell::sync::OnceCell;
385#[doc(hidden)]
386pub use DefaultHandler as DefaultContext;
387#[doc(hidden)]
388pub use EyreHandler as EyreContext;
389#[doc(hidden)]
390pub use Report as ErrReport;
391/// Compatibility re-export of `Report` for interopt with `anyhow`
392pub use Report as Error;
393/// Compatibility re-export of `WrapErr` for interopt with `anyhow`
394pub use WrapErr as Context;
395
396/// The core error reporting type of the library, a wrapper around a dynamic error reporting type.
397///
398/// `Report` works a lot like `Box<dyn std::error::Error>`, but with these
399/// differences:
400///
401/// - `Report` requires that the error is `Send`, `Sync`, and `'static`.
402/// - `Report` guarantees that a backtrace is available, even if the underlying
403/// error type does not provide one.
404/// - `Report` is represented as a narrow pointer &mdash; exactly one word in
405/// size instead of two.
406///
407/// # Display representations
408///
409/// When you print an error object using "{}" or to_string(), only the outermost underlying error
410/// is printed, not any of the lower level causes. This is exactly as if you had called the Display
411/// impl of the error from which you constructed your eyre::Report.
412///
413/// ```console
414/// Failed to read instrs from ./path/to/instrs.json
415/// ```
416///
417/// To print causes as well using eyre's default formatting of causes, use the
418/// alternate selector "{:#}".
419///
420/// ```console
421/// Failed to read instrs from ./path/to/instrs.json: No such file or directory (os error 2)
422/// ```
423///
424/// The Debug format "{:?}" includes your backtrace if one was captured. Note
425/// that this is the representation you get by default if you return an error
426/// from `fn main` instead of printing it explicitly yourself.
427///
428/// ```console
429/// Error: Failed to read instrs from ./path/to/instrs.json
430///
431/// Caused by:
432/// No such file or directory (os error 2)
433///
434/// Stack backtrace:
435/// 0: <E as eyre::context::ext::StdError>::ext_report
436/// at /git/eyre/src/backtrace.rs:26
437/// 1: core::result::Result<T,E>::map_err
438/// at /git/rustc/src/libcore/result.rs:596
439/// 2: eyre::context::<impl eyre::WrapErr<T,E,H> for core::result::Result<T,E>>::wrap_err_with
440/// at /git/eyre/src/context.rs:58
441/// 3: testing::main
442/// at src/main.rs:5
443/// 4: std::rt::lang_start
444/// at /git/rustc/src/libstd/rt.rs:61
445/// 5: main
446/// 6: __libc_start_main
447/// 7: _start
448/// ```
449///
450/// To see a conventional struct-style Debug representation, use "{:#?}".
451///
452/// ```console
453/// Error {
454/// msg: "Failed to read instrs from ./path/to/instrs.json",
455/// source: Os {
456/// code: 2,
457/// kind: NotFound,
458/// message: "No such file or directory",
459/// },
460/// }
461/// ```
462///
463/// If none of the built-in representations are appropriate and you would prefer
464/// to render the error and its cause chain yourself, it can be done by defining
465/// your own [`EyreHandler`] and [`hook`] to use it.
466///
467/// [`EyreHandler`]: trait.EyreHandler.html
468/// [`hook`]: fn.set_hook.html
469#[must_use]
470pub struct Report {
471 inner: ManuallyDrop<Box<ErrorImpl<()>>>,
472}
473
474type ErrorHook =
475 Box<dyn Fn(&(dyn StdError + 'static)) -> Box<dyn EyreHandler> + Sync + Send + 'static>;
476
477static HOOK: OnceCell<ErrorHook> = OnceCell::new();
478
479/// Error indicating that `set_hook` was unable to install the provided ErrorHook
480#[derive(Debug, Clone, Copy)]
481pub struct InstallError;
482
483impl core::fmt::Display for InstallError {
484 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
485 f.write_str(data:"cannot install provided ErrorHook, a hook has already been installed")
486 }
487}
488
489impl StdError for InstallError {}
490
491/// Install the provided error hook for constructing EyreHandlers when converting
492/// Errors to Reports
493///
494/// # Details
495///
496/// To customize the format and content of error reports from `eyre` you must
497/// first define a new `EyreHandler` type to capture and store the extra context
498/// and to define the format of how to display the chain of errors and this
499/// stored context. Once this type has been defined you must also define a global
500/// hook used to construct these handlers whenever `Report`s are constructed.
501///
502/// # Examples
503///
504/// ```rust,should_panic
505/// use backtrace::Backtrace;
506/// use eyre::EyreHandler;
507/// use std::error::Error;
508/// use std::{fmt, iter};
509///
510/// fn main() -> eyre::Result<()> {
511/// // Install our custom eyre report hook for constructing our custom Handlers
512/// install().unwrap();
513///
514/// // construct a report with, hopefully, our custom handler!
515/// let mut report = eyre::eyre!("hello from custom error town!");
516///
517/// // manually set the custom msg for this report after it has been constructed
518/// if let Some(handler) = report.handler_mut().downcast_mut::<Handler>() {
519/// handler.custom_msg = Some("you're the best users, you know that right???");
520/// }
521///
522/// // print that shit!!
523/// Err(report)
524/// }
525///
526/// // define a handler that captures backtraces unless told not to
527/// fn install() -> Result<(), impl Error> {
528/// let capture_backtrace = std::env::var("RUST_BACKWARDS_TRACE")
529/// .map(|val| val != "0")
530/// .unwrap_or(true);
531///
532/// let hook = Hook { capture_backtrace };
533///
534/// eyre::set_hook(Box::new(move |e| Box::new(hook.make_handler(e))))
535/// }
536///
537/// struct Hook {
538/// capture_backtrace: bool,
539/// }
540///
541/// impl Hook {
542/// fn make_handler(&self, _error: &(dyn Error + 'static)) -> Handler {
543/// let backtrace = if self.capture_backtrace {
544/// Some(Backtrace::new())
545/// } else {
546/// None
547/// };
548///
549/// Handler {
550/// backtrace,
551/// custom_msg: None,
552/// }
553/// }
554/// }
555///
556/// struct Handler {
557/// // custom configured backtrace capture
558/// backtrace: Option<Backtrace>,
559/// // customizable message payload associated with reports
560/// custom_msg: Option<&'static str>,
561/// }
562///
563/// impl EyreHandler for Handler {
564/// fn debug(&self, error: &(dyn Error + 'static), f: &mut fmt::Formatter<'_>) -> fmt::Result {
565/// if f.alternate() {
566/// return fmt::Debug::fmt(error, f);
567/// }
568///
569/// let errors = iter::successors(Some(error), |error| (*error).source());
570///
571/// for (ind, error) in errors.enumerate() {
572/// write!(f, "\n{:>4}: {}", ind, error)?;
573/// }
574///
575/// if let Some(backtrace) = self.backtrace.as_ref() {
576/// writeln!(f, "\n\nBacktrace:\n{:?}", backtrace)?;
577/// }
578///
579/// if let Some(msg) = self.custom_msg.as_ref() {
580/// writeln!(f, "\n\n{}", msg)?;
581/// }
582///
583/// Ok(())
584/// }
585/// }
586/// ```
587pub fn set_hook(hook: ErrorHook) -> Result<(), InstallError> {
588 HOOK.set(hook).map_err(|_| InstallError)
589}
590
591#[cfg_attr(track_caller, track_caller)]
592#[cfg_attr(not(track_caller), allow(unused_mut))]
593fn capture_handler(error: &(dyn StdError + 'static)) -> Box<dyn EyreHandler> {
594 #[cfg(not(feature = "auto-install"))]
595 let hook = HOOK
596 .get()
597 .expect("a handler must always be installed if the `auto-install` feature is disabled")
598 .as_ref();
599
600 #[cfg(feature = "auto-install")]
601 let hook: &(dyn Fn(&dyn Error) -> Box<…> + Sync + Send) = HOOK&Box … + Sync + Send>
602 .get_or_init(|| Box::new(DefaultHandler::default_with))
603 .as_ref();
604
605 let mut handler: Box = hook(error);
606
607 #[cfg(track_caller)]
608 {
609 handler.track_caller(std::panic::Location::caller())
610 }
611
612 handler
613}
614
615impl dyn EyreHandler {
616 ///
617 pub fn is<T: EyreHandler>(&self) -> bool {
618 // Get `TypeId` of the type this function is instantiated with.
619 let t = core::any::TypeId::of::<T>();
620
621 // Get `TypeId` of the type in the trait object (`self`).
622 let concrete = self.type_id();
623
624 // Compare both `TypeId`s on equality.
625 t == concrete
626 }
627
628 ///
629 pub fn downcast_ref<T: EyreHandler>(&self) -> Option<&T> {
630 if self.is::<T>() {
631 unsafe { Some(&*(self as *const dyn EyreHandler as *const T)) }
632 } else {
633 None
634 }
635 }
636
637 ///
638 pub fn downcast_mut<T: EyreHandler>(&mut self) -> Option<&mut T> {
639 if self.is::<T>() {
640 unsafe { Some(&mut *(self as *mut dyn EyreHandler as *mut T)) }
641 } else {
642 None
643 }
644 }
645}
646
647/// Error Report Handler trait for customizing `eyre::Report`
648pub trait EyreHandler: core::any::Any + Send + Sync {
649 /// Define the report format
650 ///
651 /// Used to override the report format of `eyre::Report`
652 ///
653 /// # Example
654 ///
655 /// ```rust
656 /// use backtrace::Backtrace;
657 /// use eyre::EyreHandler;
658 /// use eyre::Chain;
659 /// use std::error::Error;
660 /// use indenter::indented;
661 ///
662 /// pub struct Handler {
663 /// backtrace: Backtrace,
664 /// }
665 ///
666 /// impl EyreHandler for Handler {
667 /// fn debug(
668 /// &self,
669 /// error: &(dyn Error + 'static),
670 /// f: &mut core::fmt::Formatter<'_>,
671 /// ) -> core::fmt::Result {
672 /// use core::fmt::Write as _;
673 ///
674 /// if f.alternate() {
675 /// return core::fmt::Debug::fmt(error, f);
676 /// }
677 ///
678 /// write!(f, "{}", error)?;
679 ///
680 /// if let Some(cause) = error.source() {
681 /// write!(f, "\n\nCaused by:")?;
682 /// let multiple = cause.source().is_some();
683 ///
684 /// for (n, error) in Chain::new(cause).enumerate() {
685 /// writeln!(f)?;
686 /// if multiple {
687 /// write!(indented(f).ind(n), "{}", error)?;
688 /// } else {
689 /// write!(indented(f), "{}", error)?;
690 /// }
691 /// }
692 /// }
693 ///
694 /// let backtrace = &self.backtrace;
695 /// write!(f, "\n\nStack backtrace:\n{:?}", backtrace)?;
696 ///
697 /// Ok(())
698 /// }
699 /// }
700 /// ```
701 fn debug(
702 &self,
703 error: &(dyn StdError + 'static),
704 f: &mut core::fmt::Formatter<'_>,
705 ) -> core::fmt::Result;
706
707 /// Override for the `Display` format
708 fn display(
709 &self,
710 error: &(dyn StdError + 'static),
711 f: &mut core::fmt::Formatter<'_>,
712 ) -> core::fmt::Result {
713 write!(f, "{}", error)?;
714
715 if f.alternate() {
716 for cause in crate::chain::Chain::new(error).skip(1) {
717 write!(f, ": {}", cause)?;
718 }
719 }
720
721 Ok(())
722 }
723
724 /// Store the location of the caller who constructed this error report
725 #[allow(unused_variables)]
726 fn track_caller(&mut self, location: &'static std::panic::Location<'static>) {}
727}
728
729/// The default provided error report handler for `eyre::Report`.
730///
731/// On nightly this supports conditionally capturing a `std::backtrace::Backtrace` if the source
732/// error did not already capture one.
733#[allow(dead_code)]
734pub struct DefaultHandler {
735 backtrace: Option<Backtrace>,
736 #[cfg(track_caller)]
737 location: Option<&'static std::panic::Location<'static>>,
738}
739
740impl DefaultHandler {
741 /// Manual hook which constructs `DefaultHandler`s.
742 ///
743 /// # Details
744 ///
745 /// When supplied to the `set_hook` function, `default_with` will cause `eyre::Report` to use
746 /// `DefaultHandler` as the error report handler.
747 ///
748 /// If the `auto-install` feature is enabled, and a user-provided hook for constructing
749 /// `EyreHandlers` was not installed using `set_hook`, `DefaultHandler::default_with`
750 /// is automatically installed as the hook.
751 ///
752 /// # Example
753 ///
754 /// ```rust,should_panic
755 /// use eyre::{DefaultHandler, eyre, InstallError, Result, set_hook};
756 ///
757 /// fn main() -> Result<()> {
758 /// install_default().expect("default handler inexplicably already installed");
759 /// Err(eyre!("hello from default error city!"))
760 /// }
761 ///
762 /// fn install_default() -> Result<(), InstallError> {
763 /// set_hook(Box::new(DefaultHandler::default_with))
764 /// }
765 ///
766 /// ```
767 #[allow(unused_variables)]
768 #[cfg_attr(not(feature = "auto-install"), allow(dead_code))]
769 pub fn default_with(error: &(dyn StdError + 'static)) -> Box<dyn EyreHandler> {
770 let backtrace = backtrace_if_absent!(error);
771
772 Box::new(Self {
773 backtrace,
774 #[cfg(track_caller)]
775 location: None,
776 })
777 }
778}
779
780impl core::fmt::Debug for DefaultHandler {
781 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
782 f&mut DebugStruct<'_, '_>.debug_struct("DefaultHandler")
783 .field(
784 name:"backtrace",
785 value:match &self.backtrace {
786 Some(_) => &"Some(Backtrace { ... })",
787 None => &"None",
788 },
789 )
790 .finish()
791 }
792}
793
794impl EyreHandler for DefaultHandler {
795 fn debug(
796 &self,
797 error: &(dyn StdError + 'static),
798 f: &mut core::fmt::Formatter<'_>,
799 ) -> core::fmt::Result {
800 use core::fmt::Write as _;
801
802 if f.alternate() {
803 return core::fmt::Debug::fmt(error, f);
804 }
805
806 write!(f, "{}", error)?;
807
808 if let Some(cause) = error.source() {
809 write!(f, "\n\nCaused by:")?;
810 let multiple = cause.source().is_some();
811 for (n, error) in crate::chain::Chain::new(cause).enumerate() {
812 writeln!(f)?;
813 if multiple {
814 write!(indenter::indented(f).ind(n), "{}", error)?;
815 } else {
816 write!(indenter::indented(f), "{}", error)?;
817 }
818 }
819 }
820
821 #[cfg(all(track_caller, feature = "track-caller"))]
822 {
823 if let Some(location) = self.location {
824 write!(f, "\n\nLocation:\n")?;
825 write!(indenter::indented(f), "{}", location)?;
826 }
827 }
828
829 #[cfg(backtrace)]
830 {
831 use std::backtrace::BacktraceStatus;
832
833 let backtrace = self
834 .backtrace
835 .as_ref()
836 .or_else(|| error.backtrace())
837 .expect("backtrace capture failed");
838 if let BacktraceStatus::Captured = backtrace.status() {
839 write!(f, "\n\nStack backtrace:\n{}", backtrace)?;
840 }
841 }
842
843 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/// ```
1096pub trait WrapErr<T, E>: context::private::Sealed {
1097 /// Wrap the error value with a new adhoc error
1098 #[cfg_attr(track_caller, track_caller)]
1099 fn wrap_err<D>(self, msg: D) -> Result<T, Report>
1100 where
1101 D: Display + Send + Sync + 'static;
1102
1103 /// Wrap the error value with a new adhoc error that is evaluated lazily
1104 /// only once an error does occur.
1105 #[cfg_attr(track_caller, track_caller)]
1106 fn wrap_err_with<D, F>(self, f: F) -> Result<T, Report>
1107 where
1108 D: Display + Send + Sync + 'static,
1109 F: FnOnce() -> D;
1110
1111 /// Compatibility re-export of wrap_err for interopt with `anyhow`
1112 #[cfg_attr(track_caller, track_caller)]
1113 fn context<D>(self, msg: D) -> Result<T, Report>
1114 where
1115 D: Display + Send + Sync + 'static;
1116
1117 /// Compatibility re-export of wrap_err_with for interopt with `anyhow`
1118 #[cfg_attr(track_caller, track_caller)]
1119 fn with_context<D, F>(self, f: F) -> Result<T, Report>
1120 where
1121 D: Display + Send + Sync + 'static,
1122 F: FnOnce() -> D;
1123}
1124
1125/// Provides the `context` method for `Option` when porting from `anyhow`
1126///
1127/// This trait is sealed and cannot be implemented for types outside of
1128/// `eyre`.
1129///
1130/// ## Why Doesn't `Eyre` impl `WrapErr` for `Option`?
1131///
1132/// `eyre` doesn't impl `WrapErr` for `Option` because `wrap_err` implies that you're creating a
1133/// new error that saves the previous error as its `source`. Calling `wrap_err` on an `Option` is
1134/// meaningless because there is no source error. `anyhow` avoids this issue by using a different
1135/// mental model where you're adding "context" to an error, though this not a mental model for
1136/// error handling that `eyre` agrees with.
1137///
1138/// Instead, `eyre` encourages users to think of each error as distinct, where the previous error
1139/// is the context being saved by the new error, which is backwards compared to anyhow's model. In
1140/// this model you're encouraged to use combinators provided by `std` for `Option` to convert an
1141/// option to a `Result`
1142///
1143/// # Example
1144///
1145/// Instead of:
1146///
1147/// ```rust
1148/// use eyre::ContextCompat;
1149///
1150/// fn get_thing(mut things: impl Iterator<Item = u32>) -> eyre::Result<u32> {
1151/// things
1152/// .find(|&thing| thing == 42)
1153/// .context("the thing wasnt in the list")
1154/// }
1155/// ```
1156///
1157/// We encourage you to use this:
1158///
1159/// ```rust
1160/// use eyre::eyre;
1161///
1162/// fn get_thing(mut things: impl Iterator<Item = u32>) -> eyre::Result<u32> {
1163/// things
1164/// .find(|&thing| thing == 42)
1165/// .ok_or_else(|| eyre!("the thing wasnt in the list"))
1166/// }
1167/// ```
1168pub trait ContextCompat<T>: context::private::Sealed {
1169 /// Compatibility version of `wrap_err` for creating new errors with new source on `Option`
1170 /// when porting from `anyhow`
1171 #[cfg_attr(track_caller, track_caller)]
1172 fn context<D>(self, msg: D) -> Result<T, Report>
1173 where
1174 D: Display + Send + Sync + 'static;
1175
1176 /// Compatibility version of `wrap_err_with` for creating new errors with new source on `Option`
1177 /// when porting from `anyhow`
1178 #[cfg_attr(track_caller, track_caller)]
1179 fn with_context<D, F>(self, f: F) -> Result<T, Report>
1180 where
1181 D: Display + Send + Sync + 'static,
1182 F: FnOnce() -> D;
1183
1184 /// Compatibility re-export of `context` for porting from `anyhow` to `eyre`
1185 #[cfg_attr(track_caller, track_caller)]
1186 fn wrap_err<D>(self, msg: D) -> Result<T, Report>
1187 where
1188 D: Display + Send + Sync + 'static;
1189
1190 /// Compatibility re-export of `with_context` for porting from `anyhow` to `eyre`
1191 #[cfg_attr(track_caller, track_caller)]
1192 fn wrap_err_with<D, F>(self, f: F) -> Result<T, Report>
1193 where
1194 D: Display + Send + Sync + 'static,
1195 F: FnOnce() -> D;
1196}
1197
1198// Not public API. Referenced by macro-generated code.
1199#[doc(hidden)]
1200pub mod private {
1201 use crate::Report;
1202 use alloc::fmt;
1203 use core::fmt::{Arguments, Debug, Display};
1204
1205 pub use alloc::format;
1206 pub use core::format_args;
1207 pub use core::result::Result::Err;
1208
1209 #[doc(hidden)]
1210 pub mod kind {
1211 pub use crate::kind::{AdhocKind, TraitKind};
1212
1213 pub use crate::kind::BoxedKind;
1214 }
1215
1216 #[cfg_attr(track_caller, track_caller)]
1217 pub fn new_adhoc<M>(message: M) -> Report
1218 where
1219 M: Display + Debug + Send + Sync + 'static,
1220 {
1221 Report::from_adhoc(message)
1222 }
1223
1224 #[doc(hidden)]
1225 #[cold]
1226 #[cfg_attr(track_caller, track_caller)]
1227 pub fn format_err(args: Arguments<'_>) -> Report {
1228 #[cfg(eyre_no_fmt_arguments_as_str)]
1229 let fmt_arguments_as_str: Option<&str> = None;
1230 #[cfg(not(eyre_no_fmt_arguments_as_str))]
1231 let fmt_arguments_as_str = args.as_str();
1232
1233 if let Some(message) = fmt_arguments_as_str {
1234 // eyre!("literal"), can downcast to &'static str
1235 Report::msg(message)
1236 } else {
1237 // eyre!("interpolate {var}"), can downcast to String
1238 Report::msg(fmt::format(args))
1239 }
1240 }
1241}
1242