---
title: Error Handling
description: Failure categories, retry behavior, and implementation guidance for robust handlers.
order: 74
---

# Error Handling

Error handling in DurableStack is run-centric: each run either succeeds, retries, or becomes terminally failed.

## Failure categories

- Transient failures: network timeouts, temporary dependency outages, throttling.
- Persistent logic/data failures: invalid payload, invariant violations, unrecoverable contract errors.

## Retry interaction

- Retry eligibility: `Attempt < MaxAttempts`.
- Retry timing: fixed delay or backoff based on job/runtime settings.
- Terminal failure: run marked `failed` when attempts are exhausted.

## Recommended handler patterns

- Keep handlers idempotent.
- Throw for truly failed execution paths.
- Avoid swallowing exceptions that should drive retries.
- Log with `RunId`, `JobName`, and `Attempt` for traceability.

## Example

```csharp
public async Task ExecuteAsync(JobContext context, CancellationToken cancellationToken)
{
    try
    {
        await _externalApiClient.PushAsync(cancellationToken);
    }
    catch (HttpRequestException ex)
    {
        _logger.LogWarning(ex,
            "Transient external call failure. Job={JobName} RunId={RunId} Attempt={Attempt}",
            context.JobName,
            context.RunId,
            context.Attempt);

        throw;
    }
}
```

## Operational recommendations

- Monitor retry and failure rates over time.
- Keep max attempts lower for side effects that are hard to deduplicate.
- Use backoff for unstable dependencies to reduce cascading load.
