# `Tinkex.Telemetry.Reporter.ExceptionHandler`
[🔗](https://github.com/North-Shore-AI/tinkex/blob/v0.4.0/lib/tinkex/telemetry/reporter/exception_handler.ex#L1)

Exception classification and cause chain traversal.

Determines whether exceptions are user errors (4xx client errors that should
not be retried) or unhandled exceptions (server errors, network failures, etc).

Traverses exception cause chains to find the root cause classification.

# `classify_exception`

```elixir
@spec classify_exception(term()) :: {:user_error, term()} | :unhandled
```

Classify an exception as either a user error or unhandled exception.

Returns:
  * `{:user_error, exception}` - if a user error is found in the exception chain
  * `:unhandled` - if no user error is found

User errors are identified by:
  * HTTP status codes 400-499 (except 408 and 429)
  * Category field set to `:user`
  * Tinkex.Error with user_error? flag

# `find_user_error_in_chain`

```elixir
@spec find_user_error_in_chain(term(), map()) :: {:ok, term()} | :not_found
```

Traverse the exception cause chain to find a user error.

Checks exception fields in order: :cause, :reason, :plug_status (4xx except 408/429),
:__cause__, :__context__. Depth-first, first match wins.

Uses a visited map to prevent infinite loops in circular references.

Returns:
  * `{:ok, exception}` - if a user error is found
  * `:not_found` - if no user error is found

---

*Consult [api-reference.md](api-reference.md) for complete listing*
