# `ClaudeWrapper.Error`
[🔗](https://github.com/genagent/claude_wrapper_ex/blob/main/lib/claude_wrapper/error.ex#L1)

Canonical error type for ClaudeWrapper.

Every operational failure in this library is returned as
`{:error, %ClaudeWrapper.Error{}}` and can also be raised (it is a
proper exception). Branch on the `:kind` atom for the failure
category; the `:reason` field plus the dedicated `:exit_code` /
`:stdout` / `:stderr` fields carry the details.

    case ClaudeWrapper.query("hi") do
      {:ok, result} -> result
      {:error, %ClaudeWrapper.Error{kind: :max_turns_exceeded}} -> :hit_limit
      {:error, %ClaudeWrapper.Error{kind: :command_failed, exit_code: code}} -> code
    end

The variant set mirrors the Rust `claude-wrapper` `Error` enum.

## Kinds

  * `:binary_not_found` -- the `claude` binary could not be launched
  * `:command_failed` -- the CLI exited non-zero (`:exit_code`,
    `:stdout`, `:stderr`)
  * `:io` -- an OS/IO error launching or talking to the CLI
    (`:reason`)
  * `:timeout` -- the call exceeded its timeout (`:reason` is the
    timeout in ms)
  * `:json` -- the CLI output could not be decoded as JSON
    (`:reason`, optional `:stdout`)
  * `:max_turns_exceeded` -- the CLI stopped at its `--max-turns`
    limit. `:reason` is a `%{cap:, cost_usd:, num_turns:,
    session_id:}` map (any field may be `nil`); `:cap` is the
    configured turn limit and `:session_id` can resume the run
  * `:max_budget_exceeded` -- the CLI stopped at its
    `--max-budget-usd` spend cap (subtype `error_max_budget_usd`).
    Distinct from `:budget_exceeded`, which is the client-side
    `ClaudeWrapper.Budget` tracker. `:reason` is a `%{cap:,
    cost_usd:, num_turns:, session_id:}` map (any field may be
    `nil`); `:cap` is the reported cap, not the actual spend, since
    claude checks the budget post-hoc and a run can overspend before
    tripping
  * `:version_mismatch` -- the CLI is older than a required minimum
    (`:reason` is `%{found:, minimum:}`)
  * `:invalid_version` -- a version string could not be parsed
    (`:reason` is the original string)
  * `:budget_exceeded` -- a client-side budget ceiling was hit
    (`:reason` is `%{total_usd:, max_usd:}`)
  * `:dangerous_not_allowed` -- a bypass query was attempted without
    the opt-in env var (`:reason` is the env var name)
  * `:duplex_closed` -- the duplex session port was already closed
  * `:turn_in_flight` -- a turn is already running on the session
  * `:duplex_control_failed` -- an interrupt/permission control
    message failed (`:reason`)
  * `:terminated` -- the session terminated while a turn was pending
  * `:cannot_defer_again` -- a permission decision was deferred twice
  * `:no_session` -- a REPL helper was used with no active session
  * `:not_found` -- a requested resource does not exist (`:reason`
    identifies it)
  * `:already_exists` -- a create-new target already exists
    (`:reason`)
  * `:invalid_stem` -- an invalid file stem / identifier (`:reason`)
  * `:no_home` -- the user home directory could not be determined
  * `:invalid_settings_json` -- a settings file is not valid JSON
    (`:reason` is `%{path:, error:}`)
  * `:settings_read_error` -- a settings file could not be read
    (`:reason` is `%{path:, error:}`)
  * `:not_a_git_repo` -- a path is not inside a git repo (`:reason`
    is the path)
  * `:git_failed` -- a `git` invocation failed (`:reason`)
  * `:git_unavailable` -- the `git` binary is not available
    (`:reason`)
  * `:invalid_tool_pattern` -- a tool pattern failed validation
    (`:reason` is the specific problem)
  * `:auth` -- an authentication failure, classified into `:reason`
    (see `t:ClaudeWrapper.Auth.auth_error_kind/0`)
  * `:invalid_render` -- a `ClaudeWrapper.Structured` module's `render/1`
    returned a value that was neither a `%ClaudeWrapper.Prompt{}` nor a
    string (`:reason` is the offending return value)
  * `:no_structured_output` -- a `ClaudeWrapper.Structured` run produced a
    result with no structured output, i.e. no `--json-schema` took effect
    (`:reason` is the `%ClaudeWrapper.Result{}`)

# `kind`

```elixir
@type kind() ::
  :binary_not_found
  | :command_failed
  | :io
  | :timeout
  | :json
  | :max_turns_exceeded
  | :max_budget_exceeded
  | :version_mismatch
  | :invalid_version
  | :budget_exceeded
  | :dangerous_not_allowed
  | :duplex_closed
  | :turn_in_flight
  | :duplex_control_failed
  | :terminated
  | :cannot_defer_again
  | :no_session
  | :not_found
  | :already_exists
  | :invalid_stem
  | :no_home
  | :invalid_settings_json
  | :settings_read_error
  | :not_a_git_repo
  | :git_failed
  | :git_unavailable
  | :invalid_tool_pattern
  | :auth
  | :invalid_render
  | :no_structured_output
```

# `t`

```elixir
@type t() :: %ClaudeWrapper.Error{
  __exception__: term(),
  exit_code: integer() | nil,
  kind: kind(),
  message: String.t() | nil,
  reason: term(),
  stderr: String.t() | nil,
  stdout: String.t() | nil
}
```

# `command_failed`

```elixir
@spec command_failed(integer(), String.t(), String.t() | nil) :: t()
```

A `:command_failed` error from a non-zero CLI exit.

# `io`

```elixir
@spec io(term()) :: t()
```

An `:io` error wrapping an underlying reason.

# `json`

```elixir
@spec json(term(), String.t() | nil) :: t()
```

A `:json` decode error, optionally carrying the raw `stdout`.

# `new`

```elixir
@spec new(
  kind(),
  keyword()
) :: t()
```

Build an error of `kind`, with optional `:message`, `:reason`,
`:exit_code`, `:stdout`, `:stderr`.

# `timeout`

```elixir
@spec timeout(non_neg_integer()) :: t()
```

A `:timeout` error (`ms` is the elapsed timeout).

---

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