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(backtrace, feature(backtrace))]
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 let backtrace = backtrace_if_absent!(error);
767
768 Box::new(Self {
769 backtrace,
770 #[cfg(track_caller)]
771 location: None,
772 })
773 }
774}
775
776impl core::fmt::Debug for DefaultHandler {
777 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
778 f.debug_struct("DefaultHandler")
779 .field(
780 "backtrace",
781 match &self.backtrace {
782 Some(_) => &"Some(Backtrace { ... })",
783 None => &"None",
784 },
785 )
786 .finish()
787 }
788}
789
790impl EyreHandler for DefaultHandler {
791 fn debug(
792 &self,
793 error: &(dyn StdError + 'static),
794 f: &mut core::fmt::Formatter<'_>,
795 ) -> core::fmt::Result {
796 use core::fmt::Write as _;
797
798 if f.alternate() {
799 return core::fmt::Debug::fmt(error, f);
800 }
801
802 write!(f, "{}", error)?;
803
804 if let Some(cause) = error.source() {
805 write!(f, "\n\nCaused by:")?;
806 let multiple = cause.source().is_some();
807 for (n, error) in crate::chain::Chain::new(cause).enumerate() {
808 writeln!(f)?;
809 if multiple {
810 write!(indenter::indented(f).ind(n), "{}", error)?;
811 } else {
812 write!(indenter::indented(f), "{}", error)?;
813 }
814 }
815 }
816
817 #[cfg(all(track_caller, feature = "track-caller"))]
818 {
819 if let Some(location) = self.location {
820 write!(f, "\n\nLocation:\n")?;
821 write!(indenter::indented(f), "{}", location)?;
822 }
823 }
824
825 #[cfg(backtrace)]
826 {
827 use std::backtrace::BacktraceStatus;
828
829 let backtrace = self
830 .backtrace
831 .as_ref()
832 .or_else(|| error.backtrace())
833 .expect("backtrace capture failed");
834 if let BacktraceStatus::Captured = backtrace.status() {
835 write!(f, "\n\nStack backtrace:\n{}", backtrace)?;
836 }
837 }
838
839 Result::Ok(())
840 }
841
842 #[cfg(track_caller)]
843 fn track_caller(&mut self, location: &'static std::panic::Location<'static>) {
844 self.location = Some(location);
845 }
846}
847
848/// Iterator of a chain of source errors.
849///
850/// This type is the iterator returned by [`Report::chain`].
851///
852/// # Example
853///
854/// ```
855/// use eyre::Report;
856/// use std::io;
857///
858/// pub fn underlying_io_error_kind(error: &Report) -> Option<io::ErrorKind> {
859/// for cause in error.chain() {
860/// if let Some(io_error) = cause.downcast_ref::<io::Error>() {
861/// return Some(io_error.kind());
862/// }
863/// }
864/// None
865/// }
866/// ```
867#[derive(Clone)]
868#[allow(missing_debug_implementations)]
869pub struct Chain<'a> {
870 state: crate::chain::ChainState<'a>,
871}
872
873/// type alias for `Result<T, Report>`
874///
875/// This is a reasonable return type to use throughout your application but also for `fn main`; if
876/// you do, failures will be printed along with a backtrace if one was captured.
877///
878/// `eyre::Result` may be used with one *or* two type parameters.
879///
880/// ```rust
881/// use eyre::Result;
882///
883/// # const IGNORE: &str = stringify! {
884/// fn demo1() -> Result<T> {...}
885/// // ^ equivalent to std::result::Result<T, eyre::Report>
886///
887/// fn demo2() -> Result<T, OtherError> {...}
888/// // ^ equivalent to std::result::Result<T, OtherError>
889/// # };
890/// ```
891///
892/// # Example
893///
894/// ```
895/// # pub trait Deserialize {}
896/// #
897/// # mod serde_json {
898/// # use super::Deserialize;
899/// # use std::io;
900/// #
901/// # pub fn from_str<T: Deserialize>(json: &str) -> io::Result<T> {
902/// # unimplemented!()
903/// # }
904/// # }
905/// #
906/// # #[derive(Debug)]
907/// # struct ClusterMap;
908/// #
909/// # impl Deserialize for ClusterMap {}
910/// #
911/// use eyre::Result;
912///
913/// fn main() -> Result<()> {
914/// # return Ok(());
915/// let config = std::fs::read_to_string("cluster.json")?;
916/// let map: ClusterMap = serde_json::from_str(&config)?;
917/// println!("cluster info: {:#?}", map);
918/// Ok(())
919/// }
920/// ```
921pub type Result<T, E = Report> = core::result::Result<T, E>;
922
923/// Provides the `wrap_err` method for `Result`.
924///
925/// This trait is sealed and cannot be implemented for types outside of
926/// `eyre`.
927///
928/// # Example
929///
930/// ```
931/// use eyre::{WrapErr, Result};
932/// use std::fs;
933/// use std::path::PathBuf;
934///
935/// pub struct ImportantThing {
936/// path: PathBuf,
937/// }
938///
939/// impl ImportantThing {
940/// # const IGNORE: &'static str = stringify! {
941/// pub fn detach(&mut self) -> Result<()> {...}
942/// # };
943/// # fn detach(&mut self) -> Result<()> {
944/// # unimplemented!()
945/// # }
946/// }
947///
948/// pub fn do_it(mut it: ImportantThing) -> Result<Vec<u8>> {
949/// it.detach().wrap_err("Failed to detach the important thing")?;
950///
951/// let path = &it.path;
952/// let content = fs::read(path)
953/// .wrap_err_with(|| format!("Failed to read instrs from {}", path.display()))?;
954///
955/// Ok(content)
956/// }
957/// ```
958///
959/// When printed, the outermost error would be printed first and the lower
960/// level underlying causes would be enumerated below.
961///
962/// ```console
963/// Error: Failed to read instrs from ./path/to/instrs.json
964///
965/// Caused by:
966/// No such file or directory (os error 2)
967/// ```
968///
969/// # Wrapping Types That Don't impl `Error` (e.g. `&str` and `Box<dyn Error>`)
970///
971/// Due to restrictions for coherence `Report` cannot impl `From` for types that don't impl
972/// `Error`. Attempts to do so will give "this type might implement Error in the future" as an
973/// error. As such, `wrap_err`, which uses `From` under the hood, cannot be used to wrap these
974/// types. Instead we encourage you to use the combinators provided for `Result` in `std`/`core`.
975///
976/// For example, instead of this:
977///
978/// ```rust,compile_fail
979/// use std::error::Error;
980/// use eyre::{WrapErr, Report};
981///
982/// fn wrap_example(err: Result<(), Box<dyn Error + Send + Sync + 'static>>) -> Result<(), Report> {
983/// err.wrap_err("saw a downstream error")
984/// }
985/// ```
986///
987/// We encourage you to write this:
988///
989/// ```rust
990/// use std::error::Error;
991/// use eyre::{WrapErr, Report, eyre};
992///
993/// fn wrap_example(err: Result<(), Box<dyn Error + Send + Sync + 'static>>) -> Result<(), Report> {
994/// err.map_err(|e| eyre!(e)).wrap_err("saw a downstream error")
995/// }
996/// ```
997///
998/// # Effect on downcasting
999///
1000/// After attaching a message of type `D` onto an error of type `E`, the resulting
1001/// `eyre::Report` may be downcast to `D` **or** to `E`.
1002///
1003/// That is, in codebases that rely on downcasting, Eyre's wrap_err supports
1004/// both of the following use cases:
1005///
1006/// - **Attaching messages whose type is insignificant onto errors whose type
1007/// is used in downcasts.**
1008///
1009/// In other error libraries whose wrap_err is not designed this way, it can
1010/// be risky to introduce messages to existing code because new message might
1011/// break existing working downcasts. In Eyre, any downcast that worked
1012/// before adding the message will continue to work after you add a message, so
1013/// you should freely wrap errors wherever it would be helpful.
1014///
1015/// ```
1016/// # use eyre::bail;
1017/// # use thiserror::Error;
1018/// #
1019/// # #[derive(Error, Debug)]
1020/// # #[error("???")]
1021/// # struct SuspiciousError;
1022/// #
1023/// # fn helper() -> Result<()> {
1024/// # bail!(SuspiciousError);
1025/// # }
1026/// #
1027/// use eyre::{WrapErr, Result};
1028///
1029/// fn do_it() -> Result<()> {
1030/// helper().wrap_err("Failed to complete the work")?;
1031/// # const IGNORE: &str = stringify! {
1032/// ...
1033/// # };
1034/// # unreachable!()
1035/// }
1036///
1037/// fn main() {
1038/// # #[cfg(not(feature = "auto-install"))]
1039/// # eyre::set_hook(Box::new(eyre::DefaultHandler::default_with)).unwrap();
1040/// let err = do_it().unwrap_err();
1041/// if let Some(e) = err.downcast_ref::<SuspiciousError>() {
1042/// // If helper() returned SuspiciousError, this downcast will
1043/// // correctly succeed even with the message in between.
1044/// # return;
1045/// }
1046/// # panic!("expected downcast to succeed");
1047/// }
1048/// ```
1049///
1050/// - **Attaching message whose type is used in downcasts onto errors whose
1051/// type is insignificant.**
1052///
1053/// Some codebases prefer to use machine-readable messages to categorize
1054/// lower level errors in a way that will be actionable to higher levels of
1055/// the application.
1056///
1057/// ```
1058/// # use eyre::bail;
1059/// # use thiserror::Error;
1060/// #
1061/// # #[derive(Error, Debug)]
1062/// # #[error("???")]
1063/// # struct HelperFailed;
1064/// #
1065/// # fn helper() -> Result<()> {
1066/// # bail!("no such file or directory");
1067/// # }
1068/// #
1069/// use eyre::{WrapErr, Result};
1070///
1071/// fn do_it() -> Result<()> {
1072/// helper().wrap_err(HelperFailed)?;
1073/// # const IGNORE: &str = stringify! {
1074/// ...
1075/// # };
1076/// # unreachable!()
1077/// }
1078///
1079/// fn main() {
1080/// # #[cfg(not(feature = "auto-install"))]
1081/// # eyre::set_hook(Box::new(eyre::DefaultHandler::default_with)).unwrap();
1082/// let err = do_it().unwrap_err();
1083/// if let Some(e) = err.downcast_ref::<HelperFailed>() {
1084/// // If helper failed, this downcast will succeed because
1085/// // HelperFailed is the message that has been attached to
1086/// // that error.
1087/// # return;
1088/// }
1089/// # panic!("expected downcast to succeed");
1090/// }
1091/// ```
1092///
1093/// # `wrap_err` vs `wrap_err_with`
1094///
1095/// `wrap_err` incurs a runtime cost even in the non-error case because it requires eagerly
1096/// constructing the error object. `wrap_err_with` avoids this cost through lazy evaluation. This
1097/// cost is proportional to the cost of the currently installed [`EyreHandler`]'s creation step.
1098/// `wrap_err` is useful in cases where an constructed error object already exists.
1099pub trait WrapErr<T, E>: context::private::Sealed {
1100 /// Wrap the error value with a new adhoc error
1101 #[cfg_attr(track_caller, track_caller)]
1102 fn wrap_err<D>(self, msg: D) -> Result<T, Report>
1103 where
1104 D: Display + Send + Sync + 'static;
1105
1106 /// Wrap the error value with a new adhoc error that is evaluated lazily
1107 /// only once an error does occur.
1108 #[cfg_attr(track_caller, track_caller)]
1109 fn wrap_err_with<D, F>(self, f: F) -> Result<T, Report>
1110 where
1111 D: Display + Send + Sync + 'static,
1112 F: FnOnce() -> D;
1113
1114 /// Compatibility re-export of wrap_err for interop with `anyhow`
1115 #[cfg_attr(track_caller, track_caller)]
1116 fn context<D>(self, msg: D) -> Result<T, Report>
1117 where
1118 D: Display + Send + Sync + 'static;
1119
1120 /// Compatibility re-export of wrap_err_with for interop with `anyhow`
1121 #[cfg_attr(track_caller, track_caller)]
1122 fn with_context<D, F>(self, f: F) -> Result<T, Report>
1123 where
1124 D: Display + Send + Sync + 'static,
1125 F: FnOnce() -> D;
1126}
1127
1128/// Provides the [`ok_or_eyre`][OptionExt::ok_or_eyre] method for [`Option`].
1129///
1130/// This trait is sealed and cannot be implemented for types outside of
1131/// `eyre`.
1132///
1133/// # Example
1134///
1135/// ```
1136/// # #[cfg(not(feature = "auto-install"))]
1137/// # eyre::set_hook(Box::new(eyre::DefaultHandler::default_with)).unwrap();
1138/// use eyre::OptionExt;
1139///
1140/// let option: Option<()> = None;
1141///
1142/// let result = option.ok_or_eyre("static str error");
1143///
1144/// assert_eq!(result.unwrap_err().to_string(), "static str error");
1145/// ```
1146///
1147/// # `ok_or_eyre` vs `ok_or_else`
1148///
1149/// If string interpolation is required for the generated [report][Report],
1150/// use [`ok_or_else`][Option::ok_or_else] instead,
1151/// invoking [`eyre!`] to perform string interpolation:
1152///
1153/// ```
1154/// # #[cfg(not(feature = "auto-install"))]
1155/// # eyre::set_hook(Box::new(eyre::DefaultHandler::default_with)).unwrap();
1156/// use eyre::eyre;
1157///
1158/// let option: Option<()> = None;
1159///
1160/// let result = option.ok_or_else(|| eyre!("{} error", "dynamic"));
1161///
1162/// assert_eq!(result.unwrap_err().to_string(), "dynamic error");
1163/// ```
1164///
1165/// `ok_or_eyre` incurs no runtime cost, as the error object
1166/// is constructed from the provided static argument
1167/// only in the `None` case.
1168pub trait OptionExt<T>: context::private::Sealed {
1169 /// Transform the [`Option<T>`] into a [`Result<T, E>`],
1170 /// mapping [`Some(v)`][Option::Some] to [`Ok(v)`][Result::Ok]
1171 /// and [`None`] to [`Report`].
1172 ///
1173 /// `ok_or_eyre` allows for eyre [`Report`] error objects
1174 /// to be lazily created from static messages in the `None` case.
1175 ///
1176 /// For dynamic error messages, use [`ok_or_else`][Option::ok_or_else],
1177 /// invoking [`eyre!`] in the closure to perform string interpolation.
1178 fn ok_or_eyre<M>(self, message: M) -> crate::Result<T>
1179 where
1180 M: Debug + Display + Send + Sync + 'static;
1181}
1182
1183/// Provides the `context` method for `Option` when porting from `anyhow`
1184///
1185/// This trait is sealed and cannot be implemented for types outside of
1186/// `eyre`.
1187///
1188/// ## Why Doesn't `Eyre` impl `WrapErr` for `Option`?
1189///
1190/// `eyre` doesn't impl `WrapErr` for `Option` because `wrap_err` implies that you're creating a
1191/// new error that saves the previous error as its `source`. Calling `wrap_err` on an `Option` is
1192/// meaningless because there is no source error. `anyhow` avoids this issue by using a different
1193/// mental model where you're adding "context" to an error, though this not a mental model for
1194/// error handling that `eyre` agrees with.
1195///
1196/// Instead, `eyre` encourages users to think of each error as distinct, where the previous error
1197/// is the context being saved by the new error, which is backwards compared to anyhow's model. In
1198/// this model you're encouraged to use combinators provided by `std` for `Option` to convert an
1199/// option to a `Result`
1200///
1201/// # Example
1202///
1203/// Instead of:
1204///
1205/// ```rust
1206/// use eyre::ContextCompat;
1207///
1208/// fn get_thing(mut things: impl Iterator<Item = u32>) -> eyre::Result<u32> {
1209/// things
1210/// .find(|&thing| thing == 42)
1211/// .context("the thing wasnt in the list")
1212/// }
1213/// ```
1214///
1215/// We encourage you to use this:
1216///
1217/// ```rust
1218/// use eyre::eyre;
1219///
1220/// fn get_thing(mut things: impl Iterator<Item = u32>) -> eyre::Result<u32> {
1221/// things
1222/// .find(|&thing| thing == 42)
1223/// .ok_or_else(|| eyre!("the thing wasnt in the list"))
1224/// }
1225/// ```
1226pub trait ContextCompat<T>: context::private::Sealed {
1227 /// Compatibility version of `wrap_err` for creating new errors with new source on `Option`
1228 /// when porting from `anyhow`
1229 #[cfg_attr(track_caller, track_caller)]
1230 fn context<D>(self, msg: D) -> Result<T, Report>
1231 where
1232 D: Display + Send + Sync + 'static;
1233
1234 /// Compatibility version of `wrap_err_with` for creating new errors with new source on `Option`
1235 /// when porting from `anyhow`
1236 #[cfg_attr(track_caller, track_caller)]
1237 fn with_context<D, F>(self, f: F) -> Result<T, Report>
1238 where
1239 D: Display + Send + Sync + 'static,
1240 F: FnOnce() -> D;
1241
1242 /// Compatibility re-export of `context` for porting from `anyhow` to `eyre`
1243 #[cfg_attr(track_caller, track_caller)]
1244 fn wrap_err<D>(self, msg: D) -> Result<T, Report>
1245 where
1246 D: Display + Send + Sync + 'static;
1247
1248 /// Compatibility re-export of `with_context` for porting from `anyhow` to `eyre`
1249 #[cfg_attr(track_caller, track_caller)]
1250 fn wrap_err_with<D, F>(self, f: F) -> Result<T, Report>
1251 where
1252 D: Display + Send + Sync + 'static,
1253 F: FnOnce() -> D;
1254}
1255
1256/// Equivalent to Ok::<_, eyre::Error>(value).
1257///
1258/// This simplifies creation of an eyre::Result in places where type inference
1259/// cannot deduce the `E` type of the result — without needing to write
1260/// `Ok::<_, eyre::Error>(value)`.
1261///
1262/// One might think that `eyre::Result::Ok(value)` would work in such cases
1263/// but it does not.
1264///
1265/// ```console
1266/// error[E0282]: type annotations needed for `std::result::Result<i32, E>`
1267/// --> src/main.rs:11:13
1268/// |
1269/// 11 | let _ = eyre::Result::Ok(1);
1270/// | - ^^^^^^^^^^^^^^^^ cannot infer type for type parameter `E` declared on the enum `Result`
1271/// | |
1272/// | consider giving this pattern the explicit type `std::result::Result<i32, E>`, where the type parameter `E` is specified
1273/// ```
1274#[allow(non_snake_case)]
1275pub fn Ok<T>(t: T) -> Result<T> {
1276 Result::Ok(t)
1277}
1278
1279// Not public API. Referenced by macro-generated code.
1280#[doc(hidden)]
1281pub mod private {
1282 use crate::Report;
1283 use alloc::fmt;
1284 use core::fmt::{Arguments, Debug, Display};
1285
1286 pub use alloc::format;
1287 pub use core::format_args;
1288 pub use core::result::Result::Err;
1289
1290 #[doc(hidden)]
1291 pub mod kind {
1292 pub use crate::kind::{AdhocKind, TraitKind};
1293
1294 pub use crate::kind::BoxedKind;
1295 }
1296
1297 #[cfg_attr(track_caller, track_caller)]
1298 pub fn new_adhoc<M>(message: M) -> Report
1299 where
1300 M: Display + Debug + Send + Sync + 'static,
1301 {
1302 Report::from_adhoc(message)
1303 }
1304
1305 #[doc(hidden)]
1306 #[cold]
1307 #[cfg_attr(track_caller, track_caller)]
1308 pub fn format_err(args: Arguments<'_>) -> Report {
1309 #[cfg(eyre_no_fmt_arguments_as_str)]
1310 let fmt_arguments_as_str: Option<&str> = None;
1311 #[cfg(not(eyre_no_fmt_arguments_as_str))]
1312 let fmt_arguments_as_str = args.as_str();
1313
1314 if let Some(message) = fmt_arguments_as_str {
1315 // eyre!("literal"), can downcast to &'static str
1316 Report::msg(message)
1317 } else {
1318 // eyre!("interpolate {var}"), can downcast to String
1319 Report::msg(fmt::format(args))
1320 }
1321 }
1322}