# `Replicant.Error`
[🔗](https://github.com/baselabs/replicant/blob/v0.3.1/lib/replicant/error.ex#L1)

A typed, value-free error.

`reason` is a stable atom; `table`, `lsn`, and `shape` carry structure only.
No row value, parameter, or decoded byte ever reaches this struct — the decode
boundary (`Replicant.Decoder.decode/1`) and the identifier validator
(`Replicant.Identifier`) are the enforcement points. `message/1` and the
derived `Inspect` render only structural fields (Critical Rule 1).

# `reason`

```elixir
@type reason() ::
  :decode_failure
  | :unsupported_message
  | :invalid_identifier
  | :sink_failed
  | :schema_change_destructive
  | :slot_invalidated
  | :config_invalid
  | :too_many_streams
  | :spill_io_failed
  | :spill_exhausted
  | :snapshot_failed
  | :snapshot_table_contended
  | :snapshot_progress_invalid
  | :checkpoint_store_failed
  | :checkpoint_store_schema_mismatch
```

# `t`

```elixir
@type t() :: %Replicant.Error{
  __exception__: true,
  lsn: Replicant.lsn() | nil,
  message: String.t() | nil,
  reason: reason(),
  shape: String.t() | nil,
  table: String.t() | nil
}
```

# `decode_failure`

```elixir
@spec decode_failure(Exception.t()) :: t()
```

Build a value-free `:decode_failure` from any exception the vendored parser
raised. The original message (which may embed raw bytes) is **discarded**; only
the exception's module name is kept on `:shape` for triage.

---

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