# `PB.Error`
[🔗](https://github.com/hansihe/pb_ex/blob/v0.2.0/pb/lib/pb/error.ex#L1)

Shared toolkit and umbrella type for PB's structured errors.

PB does not raise a single catch-all error struct. Instead each failure
category is its own `defexception`, with typed fields rather than a free-form
details map:

  * `PB.SchemaError` — schema-resolution / introspection failures
    (`unknown_message`, `unknown_enum`, `unknown_service`,
    `unknown_extension`, `invalid_schema`, `missing_imports`).
  * `PB.ValueError` — input value/shape failures (`invalid_value`,
    `value_out_of_range`, `unknown_field`, `invalid_oneof`, enum-value
    problems, `missing_required`, `message_name_mismatch`, strict-projection
    failures, `absent`, …).
  * `PB.OptionError` — option failures (`unknown_options`, `invalid_option`,
    `invalid_options`).
  * `PB.DecodeError` — structurally invalid serialized input (`malformed`
    wire bytes, `malformed_json`, `malformed_text`, `duplicate_field`).
  * `PB.AdapterError` — an adapter `to_proto`/`from_proto` callback failed.

Non-bang APIs return `{:error, error}` where `error` is one of the structs
above (`t/0`); bang APIs raise the same struct. To handle any PB error
uniformly, `rescue` the list of modules or match with `is_exception/1`.

Each struct carries `:operation` (the entry point that produced it) and
`:message_name` for context; the value/decode/adapter/schema structs also
carry a `:path` locating the offending field. This module holds the shared
pieces: the `t/0` union, the `operation`/`path_element` types, polymorphic
`prepend_path/2`, and the formatting helpers each struct's `message/1` uses.

# `operation`

```elixir
@type operation() ::
  :compile
  | :encode
  | :decode
  | :normalize
  | :json_encode
  | :json_decode
  | :text_decode
  | :text_encode
  | :message_equal
  | :introspect
  | atom()
```

The operation that produced an error.

PB's own entry points report the operations listed here. Libraries built on
PB may report PB errors from their own entry points under their own operation
atoms, such as `:validate`.

# `path_element`

```elixir
@type path_element() :: atom() | {:index, non_neg_integer()} | {:key, term()}
```

Path element used to locate the offending field in `:path`.

# `t`

```elixir
@type t() ::
  PB.SchemaError.t()
  | PB.ValueError.t()
  | PB.OptionError.t()
  | PB.DecodeError.t()
  | PB.AdapterError.t()
```

Any PB error struct returned by `{:error, _}` or raised by a bang API.

# `prepend_path`

```elixir
@spec prepend_path(t(), [path_element()]) :: t()
```

Prepends a path prefix to an error that carries a `:path`.

Polymorphic across every PB error struct; structs without a `:path` (e.g.
`PB.OptionError`) are returned unchanged. Used to attach enclosing-field
context as an error unwinds through nested encode/decode frames.

---

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