Skip to content

Custom impl Into<Diagnostic> for types that already implement Display #880

Closed
@tannerntannern

Description

@tannerntannern

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()),
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions