# `Flezha.SDK.Error`
[🔗](https://github.com/flezha/flezha_elixir_sdk/blob/v0.1.0/lib/flezha/sdk/error.ex#L1)

The one error this SDK answers anything Flezha refuses with: a stable `code`
spelled `family.snake`, a `class`, a plain `message`, the `details` the
message names, and a `hint` naming the next command when there is one.

A refusal the controller sent carries its own rendering, read by
`from_wire/1`. A refusal this SDK makes itself, a declaration or a runtime
misuse, is built by `new/2` from the catalogue of the contract set
(`crates/flz_transport/errors.json`), the one the controller and the Rust core render
from, so a code reads the same in every language.

This module is also the Elixir renderer the controller's `Flezha.Error`
shares: `render/2`, `object/1` and `render_template/2` take any map carrying
the five fields.

# `class`

```elixir
@type class() ::
  :internal
  | :invalid
  | :unreachable
  | :denied
  | :not_found
  | :conflict
  | :unavailable
```

# `t`

```elixir
@type t() :: %Flezha.SDK.Error{
  class: class(),
  code: String.t(),
  details: %{optional(String.t()) =&gt; term()},
  hint: String.t() | nil,
  message: String.t()
}
```

# `catalogue`

```elixir
@spec catalogue() :: map()
```

The catalogue as it was compiled in.

# `details_json`

```elixir
@spec details_json(map()) :: String.t()
```

`details` as the compact, key-sorted JSON object the wire carries.

# `exit_code`

```elixir
@spec exit_code(%{class: class()}) :: pos_integer()
```

The exit code a class answers.

# `from_document`

```elixir
@spec from_document(String.t()) :: t() | nil
```

The error a JSON error document carries (`{"error": {...}}`), as the core and
the controller render it; `nil` when `document` is not one.

# `from_object`

```elixir
@spec from_object(term()) :: t() | nil
```

The error a decoded error object (`code`, `class`, `message`, `details`,
`hint`) carries; `nil` when it names no code.

# `from_wire`

```elixir
@spec from_wire(map() | nil) :: t() | nil
```

The error a controller reply carried as a wire `Error` message; `nil` for a
reply that carries none.

# `new`

```elixir
@spec new(String.t(), map() | keyword()) :: t()
```

The error `code` names, its templates filled from `details`. A code the
catalogue does not know is `internal.uncatalogued`, naming it.

# `object`

```elixir
@spec object(map()) :: String.t()
```

The `{code, class, message, details, hint}` object, as JSON with a fixed key order.

# `plain_details`

```elixir
@spec plain_details(map()) :: map()
```

Details a caller can read without knowing Elixir: string keys, and values
that are text, numbers, booleans, lists or string-keyed objects. Any other
term is its inspect.

# `render`

```elixir
@spec render(map(), :text | :json | String.t()) :: String.t()
```

`:text` is `error: <message> (<code>)` and a `hint:` line; `:json` the one-line document.

# `render_template`

```elixir
@spec render_template(String.t(), map()) :: String.t()
```

`template` with every `{key}` replaced by `details[key]` as text: a string as
written, a list of strings joined by `, `, anything else as compact JSON. A
key the details do not carry is left as written.

---

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