Skip to content

Add OriginalException property to TaskFailureDetails for granular retry logic#539

Closed
Copilot wants to merge 5 commits intomainfrom
copilot/provide-full-exception-details
Closed

Add OriginalException property to TaskFailureDetails for granular retry logic#539
Copilot wants to merge 5 commits intomainfrom
copilot/provide-full-exception-details

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Dec 7, 2025

The TaskFailureDetails class provides type information (ErrorType, ErrorMessage) but not the actual exception object, preventing fine-grained retry decisions based on specific properties like SQL transient error detection or HTTP status codes.

Changes

  • Added OriginalException property to TaskFailureDetails: Nullable Exception? property that preserves the original exception when available
  • Updated exception capture: FromException() and ToTaskFailureDetails() now preserve exceptions from Core wrappers
  • Tests: Unit tests covering property access, nested exceptions, and serialization nullability; integration test documenting distributed limitations

Usage

RetryPolicy retryPolicy = new(3, TimeSpan.FromSeconds(1))
{
    HandleFailure = details =>
    {
        // Access specific exception properties
        if (details.OriginalException is ApiException api)
            return api.StatusCode == 404;
        
        // Fallback when null (e.g., after gRPC serialization)
        return details.IsCausedBy<TransientException>();
    }
};

Limitations

OriginalException is null when TaskFailureDetails is deserialized from storage or received via gRPC, as exceptions aren't serializable. Use IsCausedBy<T>() for type-based decisions in distributed scenarios.

Original prompt

This section details on the original issue you should resolve

<issue_title>Provide Full Exception Details for Retry Handling</issue_title>
<issue_description>Description:

In the current implementation of durabletask-dotnet, the TaskFailureDetails class is passed as a Func argument for retry logic, but it only provides limited information. Specifically, the actual exception details are not fully available, which complicates retry scenarios where granular control over exception handling is required. In #314 HandleFailure method was introduced, to allow TaskFailureDetails filtering on RetryPolicy, so now it is possible to use both backoff coefficient and basic exception filtering. The problem is, TaskFailureDetails contains very little information about the real exception, and it doesn't fit some scenarios.

Use Case:
I need to retry on two types of transient errors:

  1. When SqlServerTransientExceptionDetector.ShouldRetryOn(Exception ex) resolves to true.
  2. When the exception is an ApiException with a status code of 400, 401, or 404.

Unfortunately, the current TaskFailureDetails implementation does not provide the full exception details, making it impossible to inspect the original exception. This issue hinders scenarios where both transient database issues and HTTP API failures need to be handled in the same orchestration.

Suggested Solutions:
Would it be feasible to either:

  • Serialize the original Exception into TaskFailureDetails so that users have access to full exception details?
  • Or, if TaskFailureDetails shouldn’t grow too much, introduce an alternative flow that allows accessing the original exception?

Additionally, there was a line in the codebase:

public Func<Exception, Task<bool>>? HandleAsync { get; set; }
This function seems to fit my use case more closely but was left unimplemented. Is there a specific reason why it wasn’t implemented?

Why This Matters:
Retry policies are commonly used to handle transient issues like database connection problems or temporary service unavailability. However, without full exception details, it’s challenging to make fine-tuned decisions about when and how to retry.

This enhancement would significantly improve the flexibility of retry logic by allowing users to filter retries based on the complete exception context.

Looking forward to your thoughts and feedback!
@cgillum</issue_description>

<agent_instructions>investigate and fix if this is still an issue</agent_instructions>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 2 commits December 7, 2025 03:25
Co-authored-by: YunchuWang <12449837+YunchuWang@users.noreply.github.com>
Co-authored-by: YunchuWang <12449837+YunchuWang@users.noreply.github.com>
Assert.NotNull(details.OriginalException);
CustomException? retrievedException = details.OriginalException as CustomException;
Assert.NotNull(retrievedException);
Assert.Equal(404, retrievedException.StatusCode);
Assert.NotNull(details.OriginalException);
SqlException? retrievedException = details.OriginalException as SqlException;
Assert.NotNull(retrievedException);
Assert.True(retrievedException.IsTransient);
Comment on lines +891 to +900
if (taskFailureDetails.OriginalException != null)
{
// When OriginalException is available (same-process scenarios),
// users can access specific exception properties
if (taskFailureDetails.OriginalException is ApiException apiException)
{
// Example: Only retry on specific HTTP status codes
return apiException.StatusCode == 404;
}
}
…ization

Co-authored-by: YunchuWang <12449837+YunchuWang@users.noreply.github.com>
Copilot AI changed the title [WIP] Improve exception details in retry handling Add OriginalException property to TaskFailureDetails for granular retry logic Dec 7, 2025
Copilot AI requested a review from YunchuWang December 7, 2025 03:35

public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Provide Full Exception Details for Retry Handling

2 participants