❯ cargo run --example usage Error: 0: Unable to read config 1: No such file or directory (os error 2) ━━━━━━━━━━━━━━━━━━━━━━━━━━━ SPANTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0: usage::read_file with path="fake_file" at examples/usage.rs:32 1: usage::read_config at examples/usage.rs:38 Suggestion: try using a file that exists next time Backtrace omitted. Run with RUST_BACKTRACE=1 environment variable to display it. Run with RUST_BACKTRACE=full to include source snippets.
❯ cargo run --example usage Error: 0: Unable to read config 1: No such file or directory (os error 2) ━━━━━━━━━━━━━━━━━━━━━━━━━━━ SPANTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0: usage::read_file with path="fake_file" at examples/usage.rs:32 1: usage::read_config at examples/usage.rs:38 Suggestion: try using a file that exists next time Backtrace omitted. Run with RUST_BACKTRACE=1 environment variable to display it. Run with RUST_BACKTRACE=full to include source snippets.
❯ cargo run --example usage Error: 0: Unable to read config 1: No such file or directory (os error 2) ━━━━━━━━━━━━━━━━━━━━━━━━━━━ SPANTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0: usage::read_file with path="fake_file" at examples/usage.rs:32 1: usage::read_config at examples/usage.rs:38 Suggestion: try using a file that exists next time Backtrace omitted. Run with RUST_BACKTRACE=1 environment variable to display it. Run with RUST_BACKTRACE=full to include source snippets.
❯ cargo run --example usage Error: 0: Unable to read config 1: No such file or directory (os error 2) ━━━━━━━━━━━━━━━━━━━━━━━━━━━ SPANTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0: usage::read_file with path="fake_file" at examples/usage.rs:32 1: usage::read_config at examples/usage.rs:38 Suggestion: try using a file that exists next time Backtrace omitted. Run with RUST_BACKTRACE=1 environment variable to display it. Run with RUST_BACKTRACE=full to include source snippets.
❯ cargo run --example usage Error: 0: Unable to read config 1: No such file or directory (os error 2) ━━━━━━━━━━━━━━━━━━━━━━━━━━━ SPANTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0: usage::read_file with path="fake_file" at examples/usage.rs:32 1: usage::read_config at examples/usage.rs:38 Suggestion: try using a file that exists next time Backtrace omitted. Run with RUST_BACKTRACE=1 environment variable to display it. Run with RUST_BACKTRACE=full to include source snippets.
❯ RUST_BACKTRACE=1 cargo run --example usage // ... ━━━━━━━━━━━━━━━━━━━━━━━━━━━ BACKTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━ ⋮ 5 frames hidden ⋮ 6: usage::read_file::h10b2389c2b814452 at /home/jlusby/git/yaahc/color-eyre/examples/usage.rs:35 7: usage::read_config::hf7150b146edb25d9 at /home/jlusby/git/yaahc/color-eyre/examples/usage.rs:40 8: usage::main::hc3df11a6ea0d044d at /home/jlusby/git/yaahc/color-eyre/examples/usage.rs:11 ⋮ 10 frames hidden ⋮ // ... Run with RUST_BACKTRACE=full to include source snippets.
❯ RUST_BACKTRACE=1 cargo run --example usage // ... ━━━━━━━━━━━━━━━━━━━━━━━━━━━ BACKTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━ ⋮ 5 frames hidden ⋮ 6: usage::read_file::h10b2389c2b814452 at /home/jlusby/git/yaahc/color-eyre/examples/usage.rs:35 7: usage::read_config::hf7150b146edb25d9 at /home/jlusby/git/yaahc/color-eyre/examples/usage.rs:40 8: usage::main::hc3df11a6ea0d044d at /home/jlusby/git/yaahc/color-eyre/examples/usage.rs:11 ⋮ 10 frames hidden ⋮ // ... Run with RUST_BACKTRACE=full to include source snippets.
❯ RUST_BACKTRACE=1 cargo run --example custom_filter // ... ━━━━━━━━━━━━━━━━━━━━━━━━━━━ BACKTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━ ⋮ 5 frames hidden ⋮ 6: custom_filter::read_file::h0afee8fe0960bf02 at /home/jlusby/git/yaahc/color-eyre/examples/custom_filter.rs:53 7: custom_filter::read_config::h6622065848c69b29 at /home/jlusby/git/yaahc/color-eyre/examples/custom_filter.rs:58 ⋮ 11 frames hidden ⋮ // ... Run with RUST_BACKTRACE=full to include source snippets.
❯ RUST_BACKTRACE=1 cargo run --example panic_hook --no-default-features The application panicked (crashed). Message: No such file or directory (os error 2) Location: examples/panic_hook.rs:37 ━━━━━━━━━━━━━━━━━━━━━━━━━━━ BACKTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━ ⋮ 13 frames hidden ⋮ 14: panic_hook::read_file::h1a2c1d2710c16ca9 at /home/jlusby/git/yaahc/color-eyre/examples/panic_hook.rs:37 15: panic_hook::read_config::h2751dcca3305a9a3 at /home/jlusby/git/yaahc/color-eyre/examples/panic_hook.rs:43 ⋮ 11 frames hidden ⋮ Run with COLORBT_SHOW_HIDDEN=1 environment variable to disable frame filtering. Run with RUST_BACKTRACE=full to include source snippets.
❯ cargo run --example custom_section Error: 0: the cat could not be got 1: cmd exited unsuccessfully Command: "git" "cat" Stderr: git: 'cat' is not a git command. See 'git --help'. The most similar commands are clean mktag stage stash tag var Suggestion: Maybe that isn't what git is for...
❯ cargo run --example multiple_errors Error: 0: encountered multiple errors Error: 0: The task could not be completed 1: The task you ran encountered an error Error: 0: The machine is unreachable 1: The machine you're connecting to is actively on fire Error: 0: The file could not be parsed 1: The file you're parsing is literally written in c++ instead of rust, what the hell
// if the index is past the end of the slice
} else if self.end > slice.len() {
panic!(
"index {} out of range for slice of length {}",
self.end,
slice.len()
);
}
// if the index is past the end of the slice
} else if self.end > slice.len() {
panic!(
"index {} out of range for slice of length {}",
self.end,
slice.len()
);
}
#[must_use]
enum Result<T, E> {
/// Contains the success value
Ok(T),
/// Contains the error value
Err(E),
}
match result {
Ok(success) => println!("we got the value {}!", success),
Err(error) => println!("uh oh we got an error: {}", error),
}
?
?
let config = match get_config() {
Ok(success_value) => success_value,
Err(error_value) => return Err(Error::from(error_value)),
};
// vs
let config = get_config()?;
?
match
or downcast
drop
or unwrap
panic!
catch_unwind
pub trait Error: Debug + Display {
fn source(&self) -> Option<&(dyn Error + 'static)> {
None
}
fn backtrace(&self) -> Option<&Backtrace> {
None
}
}
#[derive(Debug)]
struct DeserializeError;
impl std::fmt::Display for DeserializeError {
fn fmt(
&self,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
write!(f, "unable to deserialize type")
}
}
impl std::error::Error for DeserializeError {}
fn report(error: &(dyn std::error::Error + 'static)) {
print!("Error:");
let errors =
std::iter::successors(Some(error), |e| e.source());
for (ind, error) in errors.enumerate() {
print!("\n {}: {}", ind, error);
}
if let Some(backtrace) = error.backtrace() {
print!("\n\nBacktrace: {}", backtrace);
}
}
trait GoError {
fn msg(&self) -> String;
}
trait CppError {
fn msg(&self) -> &'spooky str;
}
ERROR read_config:read_file{path="fake_file"}: Error: Unable to read config: No such file or directory (os error 2) // vs Error: 0: Unable to read config 1: No such file or directory (os error 2) ━━━━━━━━━━━━━━━━━━━━━━━━━━━ SPANTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0: usage::read_file with path="fake_file" at examples/usage.rs:52 1: usage::read_config at examples/usage.rs:58
ERROR read_config:read_file{path="fake_file"}: Error: Unable to read config: No such file or directory (os error 2) // vs Error: 0: Unable to read config 1: No such file or directory (os error 2) ━━━━━━━━━━━━━━━━━━━━━━━━━━━ SPANTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0: usage::read_file with path="fake_file" at examples/usage.rs:52 1: usage::read_config at examples/usage.rs:58
ERROR read_config:read_file{path="fake_file"}: Error: Unable to read config: No such file or directory (os error 2) // vs Error: 0: Unable to read config 1: No such file or directory (os error 2) ━━━━━━━━━━━━━━━━━━━━━━━━━━━ SPANTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0: usage::read_file with path="fake_file" at examples/usage.rs:52 1: usage::read_config at examples/usage.rs:58
Error:
0: ERROR MESSAGE
at LOCATION
1: SOURCE'S ERROR MESSAGE
at SOURCE'S LOCATION
2: SOURCE'S SOURCE'S ERROR MESSAGE
...
trait CommandExt {
fn output2(&mut self) -> Result<String, eyre::Report>;
}
impl CommandExt for std::process::Command {
fn output2(&mut self) -> Result<String, eyre::Report> {
let output = self.output()?;
let stdout = String::from_utf8_lossy(&output.stdout)
.into_owned();
if output.status.success() {
Ok(stdout)
} else {
Err(eyre!("command exited unsuccessfully"))
}
}
}
❯ cargo run Error: 0: command exited unsuccessfully
impl CommandExt for std::process::Command {
fn output2(&mut self) -> Result<String, eyre::Report> {
let output = self.output()?;
let stdout = String::from_utf8_lossy(&output.stdout).into_owned();
if output.status.success() {
Ok(stdout)
} else {
let cmd = format!("{:?}", self);
Err(eyre!("command exited unsuccessfully"))
.section(cmd.header("Command:"))
}
}
}
❯ cargo run Error: 0: command exited unsuccessfully Command: "git" "cat"
fn main() -> Result<(), eyre::Report> {
color_eyre::install()?;
let _ = std::process::Command::new("git")
.arg("cat")
.output2()?;
Ok(())
}
fn main() -> Result<(), eyre::Report> {
color_eyre::install()?;
let _ = std::process::Command::new("git")
.arg("cat")
.output2()
.wrap_err("the cat could not be got")?;
Ok(())
}
❯ cargo run Error: 0: the cat could not be got 1: command exited unsuccessfully Command: "git" "cat"
let stdout = String...
if output.status.success() {
Ok(stdout)
} else {
let cmd = format!("{:?}", self);
let stderr =
String::from_utf8_lossy(&output.stderr)
.into_owned();
Err(eyre!("command exited unsuccessfully"))
.section(cmd.header("Command:"))
.section(stdout.header("Stdout:"))
.section(stderr.header("Stderr:"))
}
}
}
❯ cargo run Error: 0: the cat could not be got 1: command exited unsuccessfully Command: "git" "cat" Stderr: git: 'cat' is not a git command. See 'git --help'. The most similar commands are clean mktag stage stash tag var
From<E: Error>
Error
anyhow::Error
eyre::Report
Box<dyn Error>
#[derive(Debug)]
pub enum DataStoreError {
Disconnect(io::Error),
Redaction(String),
InvalidHeader {
expected: String,
found: String,
},
}
#[derive(Debug, thiserror::Error)]
pub enum DataStoreError {
Disconnect(io::Error),
Redaction(String),
InvalidHeader {
expected: String,
found: String,
},
}
#[derive(Debug, thiserror::Error)]
pub enum DataStoreError {
#[error("data store disconnected")]
Disconnect(io::Error),
#[error("the data for key `{0}` is not available")]
Redaction(String),
#[error("invalid header (expected {expected:?}, found {found:?})")]
InvalidHeader {
expected: String,
found: String,
},
}
#[derive(Debug, thiserror::Error)]
pub enum DataStoreError {
#[error("data store disconnected")]
Disconnect(#[source] io::Error),
#[error("the data for key `{0}` is not available")]
Redaction(String),
#[error("invalid header (expected {expected:?}, found {found:?})")]
InvalidHeader {
expected: String,
found: String,
},
}
#[derive(Debug, thiserror::Error)]
pub enum DataStoreError {
#[error("data store disconnected")]
Disconnect(#[from] io::Error),
#[error("the data for key `{0}` is not available")]
Redaction(String),
#[error("invalid header (expected {expected:?}, found {found:?})")]
InvalidHeader {
expected: String,
found: String,
},
}
#[derive(Debug, thiserror::Error, displaydoc::Display)]
pub enum DataStoreError {
/// data store disconnected
Disconnect(#[from] io::Error),
/// the data for key `{0}` is not available
Redaction(String),
/// invalid header (expected {expected:?}, found {found:?})
InvalidHeader {
expected: String,
found: String,
},
}
#[derive(Debug, Snafu)]
enum Error {
#[snafu(display("Unable to read configuration from {}: {}", path.display(), source))]
ReadConfiguration { source: io::Error, path: PathBuf },
}
fn process_data() -> Result<(), Error> {
let path = "config.toml";
let configuration = fs::read_to_string(path)
// wrap error while capturing `path` as context
.context(ReadConfiguration { path })?;
Ok(())
}
// Construct an ad-hoc error
Err(eyre!("file not found"))?
// Constructing an ad-hoc wrapping error
fallible_fn()
.wrap_err("failed operation")?;
#[derive(Debug, Display, Error)]
pub enum Error {
/// Could not deserialize type
Deserialize{
source: io::Error,
},
}
#[non_exhaustive]
#[derive(Debug, Display, Error)]
pub enum Error {
/// Could not deserialize type
Deserialize{
source: io::Error,
},
}
#[non_exhaustive]
#[derive(Debug, Display, Error)]
pub enum Error {
/// Could not deserialize type
#[non_exhaustive]
Deserialize{
source: io::Error,
},
}
struct LargeError { ... }
/// /!\ Doesn't impl Error /!\
fn fallible_fn() -> Result<(), Box<dyn Error>> {
// ...
}
/// Does impl Error !!! \o/
fn fallible_fn() -> Result<(), Box<LargeError>> {
// ...
}
#[fehler::throws(i32)]
fn foo(x: bool) -> i32 {
if x {
0
} else {
fehler::throw!(1);
}
}
// instrument the error
let error = std::fs::read_to_string("myfile.txt")
.in_current_span();
// extract it from `dyn Error`
let error: &(dyn std::error::Error + 'static) = &error;
assert!(error.span_trace().is_some());
#[derive(Debug, Display, Error)]
struct ExampleError;
type Error =
extracter::Bundled<ExampleError, backtrace::Backtrace>;
let error = Error::from(ExampleError);
// extract it from `dyn Error`
let error: &(dyn std::error::Error + 'static) = &error;
assert!(error.extract::<backtrace::Backtrace>().is_some());
#[derive(Display)]
/// Random error message
struct FooMessage;
let report = fallible_fn()
.wrap_err(FooMessage)
.unwrap_err();
assert!(report.downcast_ref::<FooMessage>().is_ok());