# `Splode.Error`
[🔗](https://github.com/ash-project/splode/blob/v0.3.3/lib/splode/error.ex#L5)

Use this module to create an aggregatable error.

For example:

```elixir
defmodule MyApp.Errors.InvalidArgument do
  use Splode.Error, fields: [:name, :message], class: :invalid

  def message(%{name: name, message: message}) do
    "Invalid argument #{name}: #{message}"
  end
end
```

## Message vars

After `message/1` runs, Splode scans the rendered string for `%{key}`
placeholders and replaces each with the corresponding value from the error's
`vars`. `vars` are therefore an **interpolation surface**: everything in them
is intended to be rendered into the message, so never place a value in `vars`
that is sensitive or otherwise unsafe to display. `vars` are not a private
side-channel for data you don't want in the message.

Because substitution runs against the *already rendered* string, it cannot
distinguish a `%{key}` you wrote in the template from one that appeared
because untrusted input was interpolated into the message. If you interpolate
externally-controlled text into a message, that text can name any of the
error's `vars` and have it substituted. This is only a concern when `vars`
hold something you would not want rendered — which, per the rule above, they
should not. Prefer interpolating untrusted values through `vars`
(`"...%{value}"` with `vars: [value: untrusted]`) rather than splicing them
directly into the template string.

# `t`

```elixir
@type t() :: Exception.t()
```

# `error_class?`

```elixir
@callback error_class?() :: boolean()
```

# `from_json`

```elixir
@callback from_json(map()) :: struct()
```

# `keyword_list_options?`

```elixir
@callback keyword_list_options?() :: boolean()
```

Whether a keyword list should be treated as options for building this error.

Only consulted for the module configured as a Splode's `:unknown_error`. When it returns
`true` — the default — a list that satisfies `Keyword.keyword?/1` is destructured into
`:error`, `:vars` and (if declared) `:value`, rather than being converted like any other
term.

That is surprising for terms that happen to parse as keyword lists, such as OTP exit
reasons:

```elixir
Keyword.keyword?([{:noproc, {GenServer, :call, [:some_name, :ping, 5000]}}])
#=> true
```

Returning `false` opts out: keyword lists are then converted like any other list, so
`to_error(message: "it broke")` produces two errors rather than one, and `to_error([])`
produces an empty error class rather than an unknown error. The default will change to
`false` in the next major version.

```elixir
defmodule MyApp.Errors.Unknown do
  use Splode.Error, fields: [:error], class: :unknown

  def keyword_list_options?, do: false
end
```

# `splode_error?`

```elixir
@callback splode_error?() :: boolean()
```

---

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