# `Capstan.Error`
[🔗](https://github.com/baselabs/capstan/blob/v1.3.1/lib/capstan/error.ex#L1)

A typed, **value-free** error — the boundary normaliser that scrubs a raw driver /
socket error, exception, or reason tuple to a stable atom `reason` (Rule 1, design
§ Rule 1 / F11).

No row value, column value, or connection password ever reaches a field here. A raw
reason that could embed a value — a `%SomeError{message: "... 'secret' ..."}`, a
connection keyword carrying `password:`, a nested tuple — is reduced to its structural
shape: the exception's MODULE name (never its message) on `:shape`, or a stable atom on
`:reason`. `message/1` and the derived `Inspect` render ONLY the structural fields, so
even a field a careless caller loaded with a value is never surfaced by the default
string / inspect forms.

Mirrors `replicant/lib/replicant/error.ex` — refuse to leak DB payloads at the boundary.

# `reason`

```elixir
@type reason() ::
  :config_invalid
  | :server_id_required
  | :tls_verification_unspecified
  | :invalid_sink
  | :sink_missing_handle_transaction
  | :sink_missing_checkpoint
  | :sink_missing_handle_schema_change
  | :checkpoint_store_required
  | :sink_owned_mode_unsupported
  | :start_position_current_unsupported
  | :start_position_override_unsupported
  | :sink_missing_handle_snapshot
  | :snapshot_config_drifted
  | :snapshot_table_not_captured
  | :snapshot_table_no_primary_key
  | :snapshot_pk_unsupported_type
  | :snapshot_source_mismatch
  | :snapshot_lock_unavailable
  | :snapshot_schema_drifted
  | :snapshot_chunk_read_failed
  | :snapshot_query_connect_failed
  | :snapshot_bootstrap_gtid_read_failed
  | :snapshot_bootstrap_crashed
  | :snapshot_state_read_failed
  | :snapshot_state_write_failed
  | :snapshot_coordinator_down
  | :unknown
  | atom()
```

A stable, value-free error reason atom.

# `t`

```elixir
@type t() :: %Capstan.Error{
  __exception__: term(),
  reason: reason(),
  shape: String.t() | nil
}
```

# `from`

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

Normalise any raw reason / exception / tuple into a value-free `Capstan.Error`.

  * a `Capstan.Error` passes through unchanged;
  * a value-free atom stays as the `:reason` (capstan's reasons are atoms by
    construction);
  * an exception keeps ONLY `inspect(module)` on `:shape` — its message, which may
    embed a row value or a password, is **discarded**;
  * a `{tag, payload}` tuple keeps only the atom `tag` as the reason and **discards**
    the payload (which may carry a value or the connection keyword);
  * anything else — a bare string, a map, a list — is `:unknown` with no retained
    payload (a value must never survive as a captured term).

---

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