# `Arangox.Error`
[🔗](https://github.com/ArangoDB-Community/arangox/blob/v0.8.0/lib/arangox/error.ex#L1)

The one error struct arangox produces.

Every `Arangox.Client` callback that fails returns one of these, and every
error `Arangox` hands back is one of these. There is no second error shape.

## Fields

  * `:reason` - an atom for pattern matching. Either a code from
    `Arangox.Errno` (`:arango_document_not_found`, `:arango_conflict`, ...)
    when the server supplied an `errorNum`, or a transport reason
    (`:econnrefused`, `:closed`, ...) when the failure happened below HTTP.
    `nil` only when neither is known. See `Arangox.Client` for which reasons
    mean the socket is gone. Two of them are arangox's own: `:timeout`,
    a request that ran out of time on the socket — which retires the
    connection, since arangox cannot tell where the abandoned response ended
    — and `:deadline_exceeded`, a request that was never sent because the
    caller's budget was already spent queueing for a connection, which leaves
    the connection healthy and checked in.
  * `:status` - the HTTP status, when the server responded.
  * `:error_num` - the raw ArangoDB `errorNum`, when the body supplied one.
    Always present together with `:status`, and preserved even when the
    number is absent from the vendored table and `:reason` is therefore
    `:unknown`.
  * `:endpoint` - the endpoint the failure happened against, **with any
    userinfo stripped**. See `Arangox.Endpoint.redact/1`.
  * `:message` - the human-readable message.

## Branch on `:reason`, not on `:message`

`:message` is usually **the server's own message, verbatim**. ArangoDB
controls its wording and changes it between releases, and it may contain
values from the request. It is for humans and logs. `:reason` (and `:status`
and `:error_num`) is the machine-readable surface:

    case Arangox.get(conn, path) do
      {:error, %Arangox.Error{reason: :arango_document_not_found}} -> :gone
      {:error, %Arangox.Error{reason: :arango_conflict}} -> retry()
    end

Because the message is server-controlled it is **length-bounded when
rendered**: `Exception.message/1` truncates at `message_limit/0` bytes, so a
pathological body cannot flood a log line. The `:message` field itself is
untouched.

## Nothing here carries credentials

Redaction is unconditional and has no opt-out: no message, no struct inspection and
no log line arangox produces contains authentication material. The endpoint is
redacted where it is *stored*, not only where it is rendered, so
`Exception.message/1`, `inspect/1` and the `failed to connect` line
`DBConnection` logs are all covered by the same fix.

# `t`

```elixir
@type t() :: %Arangox.Error{
  __exception__: term(),
  endpoint: Arangox.endpoint() | nil,
  error_num: non_neg_integer() | nil,
  message: binary(),
  reason: Arangox.Errno.t() | atom() | nil,
  status: pos_integer() | nil
}
```

# `message_limit`

```elixir
@spec message_limit() :: pos_integer()
```

The maximum number of bytes of `:message` that `message/1` renders.

---

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