Description
The Diagnostic
docs say:
You can define your own error container that implements
Into<Diagnostic>
if you need to handle errors based on error types.
I'm trying to do just that. However my error container already has a Display
implementation (via thiserror
). Because of the blanket impl<'a, T> From<T> for Diagnostic<'a> where T: Display
, I run into a conflicting trait implementations error.
The error makes perfect sense, but I also see no way around it without removing the Display
implementation from my code, which I'd like to keep. I feel like it's not that unusual to want a custom Into<Diagnostic>
for Display
types. Do I have other options here?
As a motivating example, I'm working in an application that uses AWS step functions, and our team wants to distinguish between retryable and non-retryable errors so the state machine can automatically retry failed lambdas when appropriate. For logging purposes, we don't care whether the error is retryable, but we need the information to bubble up to the errorType
of the lambda error output. Here's a snippet:
#[derive(Debug, thiserror::Error)]
pub enum ExecutionError {
#[error(transparent)]
Retryable(#[from] RetryableExecutionError),
#[error(transparent)]
NonRetryable(#[from] NonRetryableExecutionError),
}
#[derive(Debug, thiserror::Error)]
pub enum RetryableExecutionError {
#[error("transient database error: {0}")]
DatabaseError(String),
#[error("unexpected error: {0}")]
Unexpected(String),
}
#[derive(Debug, thiserror::Error)]
pub enum NonRetryableExecutionError {
// snip
}
impl<'a> From<ExecutionError> for Diagnostic<'a> {
fn from(value: ExecutionError) -> Diagnostic<'a> {
let (error_type, error_message) = match value {
| Self::Retryable(err) => ("Retryable", err.to_string()),
| Self::NonRetryable(err) => ("NonRetryable", err.to_string()),
};
Diagnostic {
error_type: Cow::Owned(error_type.into()),
error_message: Cow::Owned(error_message.into()),
}
}
}