# `Statifier.Lowering.Error`
[🔗](https://github.com/riddler/statifier-ex/blob/v2.0.0/lib/statifier/lowering/error.ex#L1)

Lowering's own error shape: never raised, always collected into a list.

Mirrors `Statifier.Parser.ParseError`'s shape (`reason`, `message`,
`location`) but is a plain struct rather than a `defexception` - lowering
never raises, and `Statifier.Lowering.lower/1` returns errors in a list
rather than as a single exception, so a builder that fails on its own
account can still return a partial result, the walk keeps going, and
every error found in one pass is reported rather than just the first.

The `reason` union below is declared as the complete, closed set of
shapes lowering can report. `missing_attribute/3` and `foreign_element/3`
extend it alongside the `unsupported_element`, `stray_text`,
`unexpected_root`, and `misplaced_element` constructors, each added
without reopening the type.

# `reason`

```elixir
@type reason() ::
  {:unsupported_element, name :: binary()}
  | {:misplaced_element, name :: binary(), parent :: binary()}
  | {:stray_text, text :: binary()}
  | {:unexpected_root, name :: binary()}
  | {:missing_attribute, element :: binary(), attribute :: binary()}
  | {:foreign_element, name :: binary(), uri :: binary()}
  | {:unexpected_attribute, element :: binary(), attribute :: binary()}
  | {:unsupported_attribute, element :: binary(), attribute :: binary()}
```

# `t`

```elixir
@type t() :: %Statifier.Lowering.Error{
  location: Statifier.Parser.Location.t(),
  message: binary(),
  reason: reason()
}
```

# `foreign_element`

```elixir
@spec foreign_element(
  name :: binary(),
  uri :: binary(),
  location :: Statifier.Parser.Location.t()
) ::
  t()
```

An element resolves to a namespace URI that is neither absent nor the SCXML
namespace - a genuinely foreign element, since an unprefixed element or one
declaring no `xmlns` still dispatches as SCXML's own vocabulary. `name` is
the qualified name exactly as written, prefix included, so the message
points at what the source actually said.

# `misplaced`

```elixir
@spec misplaced(
  name :: binary(),
  parent :: binary(),
  location :: Statifier.Parser.Location.t()
) :: t()
```

A known element built somewhere its parent has no slot for it.

# `missing_attribute`

```elixir
@spec missing_attribute(
  element :: binary(),
  attribute :: binary(),
  location :: Statifier.Parser.Location.t()
) :: t()
```

A required attribute is absent, so the element's struct cannot be built at
all - `<raise>` with no `event` is the first case (`:event` is
`@enforce_keys`'d on `Statifier.Document.Raise`).

# `stray_text`

```elixir
@spec stray_text(text :: binary(), location :: Statifier.Parser.Location.t()) :: t()
```

Non-whitespace text found where the element's content model has no room
for it.

`text` is the trimmed run, truncated to a readable prefix so the message
does not embed a paragraph.

# `unexpected_attribute`

```elixir
@spec unexpected_attribute(
  element :: binary(),
  attribute :: binary(),
  location :: Statifier.Parser.Location.t()
) :: t()
```

An element that takes no attributes at all (spec 4.5.2's `<else>`) was
written with one anyway - unlike `missing_attribute/3`, this never blocks
the element's own struct from being built (`<else>` needs no attribute to
build its branch), so the caller reports this alongside the struct it
still constructs, not instead of it.

# `unexpected_root`

```elixir
@spec unexpected_root(name :: binary(), location :: Statifier.Parser.Location.t()) ::
  t()
```

The document's root element is not `<scxml>` (or does not resolve to it
once namespace prefixes are resolved).

# `unsupported`

```elixir
@spec unsupported(name :: binary(), location :: Statifier.Parser.Location.t()) :: t()
```

An element name with no entry in the dispatch map.

# `unsupported_attribute`

```elixir
@spec unsupported_attribute(
  element :: binary(),
  attribute :: binary(),
  location :: Statifier.Parser.Location.t()
) :: t()
```

The spec defines `attribute` on `element`, but this engine does not
implement it - deliberately distinct from `unexpected_attribute/3`, whose
"does not accept attribute" message would be false here: the spec
defines it, this engine simply refuses to act on it. `<script src>` is
the first case (ADR-0026 decision 2: `<script>`'s `src` attribute is
rejected at load, never fetched - the same unresolved external-fetch
question `<data src>` leaves open, see ADR-0024). No struct is built when this
fires; the caller reports this error alone rather than also attempting a
build.

---

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