# `Jido.Error`
[🔗](https://github.com/agentjido/jido/blob/v2.4.0/lib/jido/error.ex#L1)

Unified error handling for the Jido ecosystem using Splode.

## Error Types

Six consolidated error types cover all failure scenarios:

| Error | Use Case |
|-------|----------|
| `ValidationError` | Invalid inputs, actions, sensors, configs |
| `ExecutionError` | Runtime failures during execution or planning |
| `RoutingError` | Signal routing and dispatch failures |
| `TimeoutError` | Operation timeouts |
| `CompensationError` | Saga compensation failures |
| `InternalError` | Unexpected system failures |

## Usage

    # Validation failures (with optional kind)
    Jido.Error.validation_error("Invalid email", kind: :input, field: :email)
    Jido.Error.validation_error("Unknown action", kind: :action, action: MyAction)

    # Execution failures (with optional phase)
    Jido.Error.execution_error("Action failed", phase: :run)
    Jido.Error.execution_error("Planning failed", phase: :planning)

    # Routing/dispatch failures
    Jido.Error.routing_error("No handler", target: "user.created")

    # Timeouts
    Jido.Error.timeout_error("Timed out", timeout: 5000)

    # Internal errors
    Jido.Error.internal_error("Unexpected failure")

## Splode Error Classes

Errors are classified for aggregation (in order of precedence):
- `:invalid` - Validation failures
- `:execution` - Runtime failures
- `:routing` - Routing/dispatch failures
- `:timeout` - Timeouts
- `:internal` - Unexpected failures

# `class`

```elixir
@type class() :: %{
  :__struct__ =&gt; class_module(),
  :__exception__ =&gt; true,
  :errors =&gt; [t()],
  :class =&gt; error_class(),
  :bread_crumbs =&gt; [String.t()],
  :vars =&gt; Keyword.t(),
  :stacktrace =&gt; Splode.Stacktrace.t() | nil,
  :context =&gt; map(),
  optional(atom()) =&gt; any()
}
```

# `class_module`

```elixir
@type class_module() ::
  Jido.Error.Internal
  | Jido.Error.Timeout
  | Jido.Error.Routing
  | Jido.Error.Execution
  | Jido.Error.Invalid
  | Splode.Error.Unknown
```

# `error_class`

```elixir
@type error_class() ::
  :internal | :timeout | :routing | :execution | :invalid | :unknown
```

# `t`

```elixir
@type t() :: %{
  :__struct__ =&gt; module(),
  :__exception__ =&gt; true,
  :class =&gt; error_class(),
  :bread_crumbs =&gt; [String.t()],
  :vars =&gt; Keyword.t(),
  :stacktrace =&gt; Splode.Stacktrace.t() | nil,
  :context =&gt; map(),
  optional(atom()) =&gt; any()
}
```

# `compensation_error`

```elixir
@spec compensation_error(String.t(), keyword() | map()) ::
  Jido.Error.CompensationError.t()
```

Creates a compensation error.

## Options

- `:original_error` - The error that triggered compensation
- `:compensated` - Whether compensation succeeded (default: false)
- `:result` - Result from successful compensation
- `:details` - Additional context map

# `execution_error`

```elixir
@spec execution_error(String.t(), keyword() | map()) :: Jido.Error.ExecutionError.t()
```

Creates an execution error.

## Options

- `:phase` - Where failure occurred: `:execution`, `:planning`
- `:details` - Additional context map
- Any other keys are merged into `details`

# `extract_message`

```elixir
@spec extract_message(any()) :: String.t()
```

Extracts the message string from a nested error structure.

# `format_nimble_config_error`

```elixir
@spec format_nimble_config_error(any(), String.t(), module()) :: String.t()
```

Formats a NimbleOptions configuration error.

# `format_nimble_validation_error`

```elixir
@spec format_nimble_validation_error(any(), String.t(), module()) :: String.t()
```

Formats a NimbleOptions validation error for parameters.

# `internal_error`

```elixir
@spec internal_error(String.t(), keyword() | map()) :: Jido.Error.InternalError.t()
```

Creates an internal error.

## Options

- `:details` - Additional context map

# `retryable?`

```elixir
@spec retryable?(term()) :: boolean()
```

Returns whether an error is safe to retry by default.

Explicit `:retry`, `:retryable`, and `:retryable?` boolean hints in structured
details override the default classification.

# `routing_error`

```elixir
@spec routing_error(String.t(), keyword() | map()) :: Jido.Error.RoutingError.t()
```

Creates a routing error.

## Options

- `:target` - The intended routing target
- `:details` - Additional context map

# `splode_error?`

# `timeout_error`

```elixir
@spec timeout_error(String.t(), keyword() | map()) :: Jido.Error.TimeoutError.t()
```

Creates a timeout error.

## Options

- `:timeout` - The timeout value in milliseconds
- `:details` - Additional context map

# `to_map`

```elixir
@spec to_map(any()) :: map()
```

Converts an error into a stable, public map.

The returned map is suitable for transport and reporting boundaries. It
includes bounded, sanitized details and never includes stacktraces by default.

Details traverse at most 4 container levels, with up to
20 entries per map or list. Scalar leaves are kept at the
depth limit, so validation paths retain field names and list indexes. Strings
are limited to 512 characters plus a truncation suffix.
Invalid UTF-8 binaries use bounded inspection.
Deeper containers and opaque terms are replaced with `[DEPTH_LIMIT]`.

# `traverse_errors`

Traverses errors, calling `fun` for each leaf error, and returns a nested
map of results grouped by each error's `path`.

See `Splode.traverse_errors/2` for full documentation.

## Example

    iex> Elixir.Jido.Error.traverse_errors(error, fn error ->
    ...>   Exception.message(error)
    ...> end)
    %{name: ["name is required"]}

# `unwrap!`

Raises an error if the result is an error, otherwise returns the result

Alternatively, you can use the `defsplode` macro, which does this automatically.

### Options

- `:error_opts` - Options to pass to `to_error/2` when converting the returned error
- `:unknown_error_opts` - Options to pass to the unknown error if the function returns only `:error`.
  not necessary if your function always returns `{:error, error}`.

### Examples

  def function(arg) do
    case do_something(arg) do
      :success -> :ok
      {:success, result} -> {:ok, result}
      {:error, error} -> {:error, error}
    end
  end

  def function!(arg) do
    YourErrors.unwrap!(function(arg))
  end

# `validation_error`

```elixir
@spec validation_error(String.t(), keyword() | map()) ::
  Jido.Error.ValidationError.t()
```

Creates a validation error.

## Options

- `:kind` - Category: `:input`, `:action`, `:sensor`, `:config`, `:state_size`
- `:subject` - The invalid value
- `:field` - Alias for `:subject` (for input validation)
- `:action` - Alias for `:subject` with `kind: :action`
- `:sensor` - Alias for `:subject` with `kind: :sensor`
- `:details` - Additional context map

## Examples

    validation_error("Invalid email", field: :email)
    validation_error("Unknown action", kind: :action, subject: MyAction)

