Struct Error
pub struct Error { /* private fields */ }Expand description
Wasmtime’s universal error type.
99% API-compatible with anyhow::Error but additionally allows recovery
from memory exhaustion (see the OutOfMemory error).
Error is similar to Box<dyn core::error::Error + Send + Sync + 'static>
but fits in one word instead of two. Additionally, Result<(), Error> also
fits in a single word.
When the "backtrace" cargo feature is enabled, Error contains a
backtrace.
§Creating an Error
Because Error implements From<E> for all types E that implement
core::error::Error + Send + Sync + 'static, you don’t usually need to
explicitly construct an Error. When you use ?-style error propagation,
it will automatically get constructed from the root cause error for you.
Most often when creating an Error, you just want to early-exit from the
function, returning Err(...). The ensure! macro
early-returns an error when a condition is not met (similar to how assert!
panics when a condition is not met) and the bail! macro
early-returns an error unconditionally.
use wasmtime::{bail, ensure, Result};
fn my_fallible_function(x: u32) -> Result<()> {
// This `ensure!` macro invocation is equivalent to
//
// if x % 2 != 0 {
// return Err(...);
// }
ensure!(x % 2 == 0, "{x} is not even!");
// This `bail!` macro invocation is equivalent to
//
// return Err(...);
bail!("oops, another error! {x}")
}If you do not want to early-return, just to create the Error, then the
format_err! macro is preferred:
use wasmtime::{format_err, Error};
let x = 42;
let my_error: Error = format_err!("whoops! {x}");If, however, you happen to require a constructor function instead of a
macro, you can use either Error::new or Error::msg:
use wasmtime::Error;
let messages = ["yikes", "uh oh", "ouch"];
let errors = messages
.into_iter()
.map(Error::msg)
.collect::<Vec<_>>();§Printing an Error
Different format strings will print an Error differently:
-
{}: Prints theDisplayof just the first error, without any of the other errors in the chain or the root cause. -
{:#}: Prints theDisplayof the first error, then (if there are more errors in the chain) a colon, then the display of the second error in the chain, etc… -
{:?}: Prints theDisplayof the first error, then (if there are more errors in the chain) a newline-separated list of the rest of the errors in the chain, and finally (if the"backtrace"cargo feature is enabled, theRUST_BACKTRACEenvironment variable is set and non-zero, and the platform is supported by Rust’s standard library’sBacktracetype) the captured backtrace is printed.This is the default formatting used when
fn main() -> wasmtime::Result<()>returns an error. -
{:#?}: Prints an internal, debugging representation of theError. We make no guarantees about its stability.
Here is an example showing the different formats for the same error:
#![cfg(all(feature = "backtrace", not(miri)))]
use wasmtime::error::{bail, Context as _, Result};
fn uno() -> Result<()> {
bail!("ouch")
}
fn dos() -> Result<()> {
uno().context("whoops")
}
fn tres() -> Result<()> {
dos().context("uh oh")
}
let error = tres().unwrap_err();
println!("{error}");
// Prints:
//
// uh oh
println!("{error:#}");
// Prints:
//
// uh oh: whoops: ouch
println!("{error:?}");
// Prints
//
// uh oh
//
// Caused by:
// 0: whoops
// 1: ouch
//
// Stack backtrace:
// <...>
// 7: example::uno
// 8: example::dos
// 9: example::tres
// 10: example::main
// <...>
println!("{error:#?}");
// Prints
//
// Error {
// <...>
// }§Converting a wasmtime::Error into an anyhow::Error
When the "anyhow" feature is enabled, there is a From<wasmtime::Error> for anyhow::Error implementation. You can always call that implementation
explicitly if needed, but ?-propagation allows the conversion to happen
seamlessly from functions that return a Result<T, wasmtime::Error> to
those that return a Result<U, anyhow::Error>.
#![cfg(feature = "anyhow")]
fn foo() -> Result<(), wasmtime::Error> {
wasmtime::bail!("decontamination failure")
}
fn bar() -> Result<(), anyhow::Error> {
foo()?; // `?` is auto-converting here!
Ok(())
}
let error = bar().unwrap_err();
assert_eq!(error.to_string(), "decontamination failure");§Converting an anyhow::Error into a wasmtime::Error
When the "anyhow" feature is enabled, there is an Error::from_anyhow
constructor that you may use to convert an anyhow::Error into a
wasmtime::Error. (Unfortunately trait coherence does not allow us a
From<anyhow::Error> for wasmtime::Error implementation.) This will
most-often be used in combination with Result::map_err:
#![cfg(feature = "anyhow")]
fn baz() -> Result<(), anyhow::Error> {
anyhow::bail!("oops I ate worms")
}
fn qux() -> Result<(), wasmtime::Error> {
baz().map_err(wasmtime::Error::from_anyhow)?;
Ok(())
}
let error = qux().unwrap_err();
assert_eq!(error.to_string(), "oops I ate worms");Implementations§
§impl Error
impl Error
pub fn new<E>(error: E) -> Error
pub fn new<E>(error: E) -> Error
Construct a new Error from a type that implements
core::error::Error.
Calling error.is::<E>() will return true for the new
error (unless there was a memory allocation failure).
This boxes the inner error, but if that box allocation fails, then this
function returns an Error where
error.is::<OutOfMemory>() is true.
§Example
use wasmtime::Error;
let error = Error::new(std::fmt::Error);pub fn msg<M>(message: M) -> Error
pub fn msg<M>(message: M) -> Error
Construct a new Error from any type that implements Debug and
Display.
Calling error.is::<M>() will return true for the new
error (unless there was a memory allocation failure).
This boxes the inner M type, but if that box allocation fails, then
this function returns an Error where
error.is::<OutOfMemory>() is true.
§Example
use wasmtime::Error;
let error = Error::msg("hello");pub fn from_boxed(error: Box<dyn Error + Send + Sync>) -> Error
pub fn from_boxed(error: Box<dyn Error + Send + Sync>) -> Error
Create an Error from a Box<dyn core::error::Error>.
This is useful when converting errors from other universal-error
libraries into this crate’s Error type. Prefer Error::from_anyhow
for converting anyhow::Errors into Errors, as that preserves
error.is::<anyhow::Error>().
Calling error.is::<Box<dyn core::error::Error + Send + Sync + 'static>>() will return true for the new error (unless
there was a memory allocation failure).
This reboxes the inner error, but if that box allocation fails, then
this function returns an Error where
error.is::<OutOfMemory>() is true.
§Example
#![cfg(all(feature = "std", feature = "anyhow"))]
use std::error::Error;
// You happen to have a boxed error trait object.
let orig_error = std::fs::read("XXX: some file that doesn't exist").unwrap_err();
let boxed_error: Box<dyn Error + Send + Sync + 'static> = Box::new(orig_error) as _;
// You can turn it into a `wasmtime::Error` via `from_boxed`.
let wasmtime_error = wasmtime::Error::from_boxed(boxed_error);pub fn from_anyhow(error: Error) -> Error
Available on crate feature anyhow only.
pub fn from_anyhow(error: Error) -> Error
anyhow only.Convert an anyhow::Error into an Error.
Calling error.is::<anyhow::Error>() will return true
for the new error (unless there was a memory allocation failure).
This reboxes the anyhow::Error, but if that box allocation fails, then
this function returns an Error where
error.is::<OutOfMemory>() is true.
§Example
#![cfg(all(feature = "std", feature = "anyhow"))]
let anyhow_error = anyhow::Error::msg("failed to flim the flam");
let wasmtime_error = wasmtime::Error::from_anyhow(anyhow_error);
assert_eq!(
wasmtime_error.to_string(),
"failed to flim the flam",
);pub fn context<C>(self, context: C) -> Error
pub fn context<C>(self, context: C) -> Error
Add additional context to this error.
The new context will show up first in the error chain, and the original error will come next.
This is similar to the Context::context trait method, but because it
is a method directly on Error, there is no need for lazily-computing
the error context (like with_context does).
Calling error.is::<C>() will return true for the new
error (unless there was a memory allocation failure) in addition to any
other types T for which it was already the case that
error.is::<T>().
This boxes the inner C type, but if that box allocation fails, then
this function returns an Error where
error.is::<OutOfMemory>() is true.
§Example
use wasmtime::Error;
let error = Error::msg("root cause");
let error = error.context("failed to bonkinate");
let error = error.context("cannot frob the blobbins");
assert!(
format!("{error:?}").contains(
r#"
cannot frob the blobbins
Caused by:
0: failed to bonkinate
1: root cause
"#.trim(),
),
);pub fn backtrace(&self) -> &Backtrace
Available on crate feature backtrace only.
pub fn backtrace(&self) -> &Backtrace
backtrace only.Get this error’s backtrace.
Backtraces will be automatically captured on initial Error creation
when all of the following conditions are met:
- This crate’s
"backtrace"cargo feature is enabled - Rust’s
std::backtrace::Backtracesupports the platform - The
RUST_BACKTRACEorRUST_LIB_BACKTRACEenvironment variables are set and non-zero
See the std::backtrace::Backtrace
documentation
for more details on backtraces.
Note that std::backtrace::Backtrace does not provide a
fallible-capture mechanism that returns an error, rather than aborting
the process, when it encounters memory exhaustion. If you require
out-of-memory error handling, do not enable this crate’s "backtrace"
cargo feature.
§Example
#![cfg(feature = "backtrace")]
use std::backtrace::BacktraceStatus;
use wasmtime::Error;
let error = Error::msg("whoops");
let backtrace = error.backtrace();
if let BacktraceStatus::Captured = backtrace.status() {
println!("error backtrace is:\n{backtrace}");
}pub fn chain(&self) -> Chain<'_> ⓘ
pub fn chain(&self) -> Chain<'_> ⓘ
Iterate over this error’s context chain.
The iterator yields &(dyn core::error::Error + 'static) items.
Iterates from the most recently added error context towards the root cause.
§Example
use wasmtime::Error;
let error = Error::msg("root cause");
let error = error.context("failed to reticulate splines");
let error = error.context("aborting launch");
let messages: Vec<_> = error.chain().map(|e| e.to_string()).collect();
assert_eq!(
messages,
["aborting launch", "failed to reticulate splines", "root cause"],
);pub fn root_cause(&self) -> &(dyn Error + 'static)
pub fn root_cause(&self) -> &(dyn Error + 'static)
Get the last error in the context chain.
§Example
use wasmtime::Error;
let error = Error::msg("ghosts");
let error = error.context("failed to reticulate splines");
let error = error.context("aborting launch");
assert_eq!(
error.root_cause().to_string(),
"ghosts",
);pub fn is<E>(&self) -> bool
pub fn is<E>(&self) -> bool
Is this an E error?
Returns true if any error in the context chain is an E.
§Example
use wasmtime::error::{Error, OutOfMemory};
let oom = Error::from(OutOfMemory::new(1234));
assert!(oom.is::<OutOfMemory>());
assert!(!oom.is::<std::num::TryFromIntError>());
// Here is an example with additional error context.
let error = Error::from(u8::try_from(u32::MAX).unwrap_err());
let error = error.context(format!("cannot convert {} into a u8", u32::MAX));
assert!(
error.is::<std::num::TryFromIntError>(),
"root cause is an int conversion failure",
);
assert!(
error.is::<String>(),
"additional context is a `String`",
);
assert!(
!error.is::<OutOfMemory>(),
"no error in the chain is an out-of-memory error",
);pub fn downcast<E>(self) -> Result<E, Error>
pub fn downcast<E>(self) -> Result<E, Error>
Downcast this error into an E, taking ownership.
If this error is an E, then Ok(E) is returned. Otherwise,
Err(self) is returned.
If there are multiple instances of E in this error’s chain, then the
first (as encountered by Error::chain’s iteration order) is
returned.
§Example
use wasmtime::error::{Error, OutOfMemory};
let error = Error::msg("whoops");
// `error` is not an `OutOfMemory`.
let downcasted = error.downcast::<OutOfMemory>();
assert!(downcasted.is_err());
// Get the original `error` back.
let error = downcasted.unwrap_err();
// `error` is an `&str`.
let downcasted = error.downcast::<&str>();
assert!(downcasted.is_ok());
assert_eq!(downcasted.unwrap(), "whoops");
// If there are multiple `E`s in the chain, the first in the chain is
// returned.
let error = Error::msg("root cause");
let error = error.context("failed to recombobulate");
assert_eq!(
error.downcast::<&str>().unwrap(),
"failed to recombobulate",
);pub fn downcast_ref<E>(&self) -> Option<&E>
pub fn downcast_ref<E>(&self) -> Option<&E>
Downcast this error into a shared &E borrow.
If this error is an E, then Some(&E) is returned. Otherwise, None
is returned.
If there are multiple instances of E in this error’s chain, then the
first (as encountered by Error::chain’s iteration order) is
returned.
§Example
use wasmtime::error::{Error, OutOfMemory};
let error = Error::msg("whoops");
// `error` is not an `OutOfMemory`.
assert!(error.downcast_ref::<OutOfMemory>().is_none());
// `error` is an `&str`.
assert!(error.downcast_ref::<&str>().is_some());
assert_eq!(*error.downcast_ref::<&str>().unwrap(), "whoops");
// If there are multiple `E`s in the chain, the first in the chain is
// returned.
let error = Error::msg("root cause");
let error = error.context("failed to recombobulate");
assert_eq!(
*error.downcast_ref::<&str>().unwrap(),
"failed to recombobulate",
);pub fn downcast_mut<E>(&mut self) -> Option<&mut E>
pub fn downcast_mut<E>(&mut self) -> Option<&mut E>
Downcast this error into an exclusive &mut E borrow.
If this error is an E, then Some(&mut E) is returned. Otherwise,
None is returned.
If there are multiple instances of E in this error’s chain, then the
first (as encountered by Error::chain’s iteration order) is
returned.
§Example
use wasmtime::error::{Error, OutOfMemory};
let mut error = Error::msg("whoops");
// `error` is not an `OutOfMemory`.
assert!(error.downcast_mut::<OutOfMemory>().is_none());
// `error` is an `&str`.
assert!(error.downcast_mut::<&str>().is_some());
assert_eq!(*error.downcast_mut::<&str>().unwrap(), "whoops");
*error.downcast_mut::<&str>().unwrap() = "yikes";
assert_eq!(*error.downcast_mut::<&str>().unwrap(), "yikes");
// If there are multiple `E`s in the chain, the first in the chain is
// returned.
let error = Error::msg("root cause");
let mut error = error.context("failed to recombobulate");
assert_eq!(
*error.downcast_mut::<&str>().unwrap(),
"failed to recombobulate",
);pub fn into_boxed_dyn_error(self) -> Box<dyn Error + Send + Sync>
pub fn into_boxed_dyn_error(self) -> Box<dyn Error + Send + Sync>
Convert this error into a Box<dyn core::error::Error>.
This is useful for integrating this crate’s Errors into other
universal-error libraries.
This functionality is also available via a From<Error> for Box<dyn core::error::Error + Send + Sync + 'static>> implementation.
§Example
#![cfg(feature = "std")]
use std::fmt;
/// A stub representing some other error library.
#[derive(Debug)]
pub struct OtherError {
inner: Box<dyn std::error::Error + Send + Sync + 'static>,
}
impl fmt::Display for OtherError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.inner, f)
}
}
impl std::error::Error for OtherError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.inner.source()
}
}
impl OtherError {
/// Create an `OtherError` from another error.
pub fn new<E>(error: E) -> Self
where
E: std::error::Error + Send + Sync + 'static,
{
OtherError { inner: Box::new(error) }
}
/// Create an `OtherError` from another, already-boxed error.
pub fn from_boxed(error: Box<dyn std::error::Error + Send + Sync + 'static>) -> Self {
OtherError { inner: error }
}
}
use wasmtime::Error;
// Create an `Error`.
let error = Error::msg("whoopsies");
// Convert it into an `OtherError`.
let error = OtherError::from_boxed(error.into_boxed_dyn_error());Trait Implementations§
§impl<T> Context<T, Error> for Result<T, Error>
impl<T> Context<T, Error> for Result<T, Error>
Auto Trait Implementations§
impl Freeze for Error
impl RefUnwindSafe for Error
impl Send for Error
impl Sync for Error
impl Unpin for Error
impl UnwindSafe for Error
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more