---
description: C# Error Handling
alwaysApply: false
---

# C# Error Handling

Exceptions for exceptional conditions. Result types for expected failures. Never swallow errors.

## Two Categories

- **Exceptions** — programming errors, infrastructure failures, genuinely unexpected
- **Result patterns** — validation failures, business rule violations, "not found"

## Guard Clauses

```csharp
ArgumentNullException.ThrowIfNull(request);
ArgumentException.ThrowIfNullOrWhiteSpace(request.Email);
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(request.Quantity);
```

## Exception Best Practices

```csharp
try {
    await _httpClient.PostAsync(url, content, ct);
} catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.TooManyRequests) {
    _logger.LogWarning(ex, "Rate limited by {Url}", url);
    await Task.Delay(retryDelay, ct);
} catch (TaskCanceledException) when (ct.IsCancellationRequested) {
    throw; // Let cancellation propagate
}
```

## Result Pattern

```csharp
public async Task<Result<User>> RegisterAsync(RegisterRequest req, CancellationToken ct) {
    if (!EmailValidator.IsValid(req.Email))
        return Result<User>.Failure(Error.Validation("Invalid email"));
    var existing = await _users.GetByEmailAsync(req.Email, ct);
    if (existing is not null)
        return Result<User>.Failure(Error.Conflict("Email registered"));
    var user = User.Create(req.Name, req.Email);
    await _users.CreateAsync(user, ct);
    return Result<User>.Success(user);
}

// In endpoint: result.Match(user => Results.Created(...), error => error.Code switch { ... });
```

## Problem Details (RFC 9457)

```csharp
builder.Services.AddProblemDetails();
app.UseExceptionHandler(); // Maps exceptions to ProblemDetails automatically
```

## Anti-Patterns

- **Catch-all that swallows** — `catch (Exception) { }` hides bugs
- **Catch and `throw new`** — loses stack trace; use `throw;` or wrap with inner exception
- **Exceptions for control flow** — use `TryGetValue`, `FirstOrDefault`
- **Log AND throw** — produces duplicate entries; choose one
