2.0.0
Breaking changes
-
Referencing keyword-named fields by a raw identifier like
{r#type}
inside a format string is no longer accepted; simply use the unraw name like{type}
(#347)This aligns thiserror with the standard library's formatting macros, which gained support for implicit argument capture later than the release of this feature in thiserror 1.x.
#[derive(Error, Debug)] #[error("... {type} ...")] // Before: {r#type} pub struct Error { pub r#type: Type, }
-
Trait bounds are no longer inferred on fields whose value is shadowed by an explicit named argument in a format message (#345)
// Before: impl<T: Octal> Display for Error<T> // After: impl<T> Display for Error<T> #[derive(Error, Debug)] #[error("{thing:o}", thing = "...")] pub struct Error<T> { thing: T, }
-
Tuple structs and tuple variants can no longer use numerical
{0}
{1}
access at the same time as supplying extra positional arguments for a format message, as this makes it ambiguous whether the number refers to a tuple field vs a different positional arg (#354)#[derive(Error, Debug)] #[error("ambiguous: {0} {}", $N)] // ^^^ Not allowed, use #[error("... {0} {n}", n = $N)] pub struct TupleError(i32);
-
Code containing invocations of thiserror's
derive(Error)
must now have a direct dependency on thethiserror
crate regardless of the error data structure's contents (#368, #369, #370, #372)
Features
-
Support disabling thiserror's standard library dependency by disabling the default "std" Cargo feature:
thiserror = { version = "2", default-features = false }
(#373) -
Support using
r#source
as field name to opt out of a field named "source" being treated as an error'sError::source()
(#350)#[derive(Error, Debug)] #[error("{source} ==> {destination}")] pub struct Error { r#source: char, destination: char, } let error = Error { source: 'S', destination: 'D' };
-
Infinite recursion in a generated Display impl now produces an
unconditional_recursion
warning (#359)#[derive(Error, Debug)] #[error("??? {self}")] pub struct Error;
-
A new attribute
#[error(fmt = path::to::myfmt)]
can be used to write formatting logic for an enum variant out-of-line (#367)#[derive(Error, Debug)] pub enum Error { #[error(fmt = demo_fmt)] Demo { code: u16, message: Option<String> }, } fn demo_fmt(code: &u16, message: &Option<String>, formatter: &mut fmt::Formatter) -> fmt::Result { write!(formatter, "{code}")?; if let Some(msg) = message { write!(formatter, " - {msg}")?; } Ok(()) }
-
Enums with an enum-level format message are now able to have individual variants that are
transparent
to supersede the enum-level message (#366)#[derive(Error, Debug)] #[error("my error {0}")] pub enum Error { Json(#[from] serde_json::Error), Yaml(#[from] serde_yaml::Error), #[error(transparent)] Other(#[from] anyhow::Error), }