# `Image.Error`
[🔗](https://github.com/elixir-image/image/blob/v0.65.0/lib/image/error.ex#L1)

The structured exception raised by `Image.*!/_arity` functions and
returned in the error half of every `{:ok, _} | {:error, _}` tuple
in the library.

Every fallible function in `Image` returns either `{:ok, value}` or
`{:error, %Image.Error{}}`. Bang variants raise the same struct.

## Fields

* `:message` — a human-readable description. Always present.

* `:reason` — a structured discriminator: an atom (`:enoent`,
  `:invalid_option`, `:unsupported_format`, …), a `{:atom, value}`
  tuple for parameterised errors, or a binary for free-form
  libvips errors that don't yet have a structured form.

* `:operation` — the high-level `Image` function that failed
  (e.g. `:open`, `:write`, `:resize`, `:draw_rect`), or `nil` if
  not known.

* `:path` — the file system path involved, when applicable.

* `:value` — the offending input value, when applicable.

## Example

    iex> {:error, %Image.Error{reason: :enoent}} = Image.open("/no/such/file.jpg")
    iex> :ok
    :ok

## Pattern matching

Callers should match on `:reason` rather than scraping `:message`:

    case Image.open(path) do
      {:ok, image} -> ...
      {:error, %Image.Error{reason: :enoent}} -> not_found_handler()
      {:error, %Image.Error{reason: {:invalid_option, opt}}} -> ...
      {:error, %Image.Error{} = err} -> raise err
    end

## Constructing

Use the standard `defexception` callback (`exception/1`) via
`raise` or by passing structured input:

    raise Image.Error, reason: :enoent, path: "/tmp/foo.jpg"

    raise Image.Error, "free form message"

    raise Image.Error, {:enoent, "/tmp/foo.jpg"}

Or convert a raw `{:error, raw}` tuple coming from libvips with
`Image.Error.wrap/2`:

    with {:error, raw} <- Vix.Vips.Operation.thumbnail(path, 256) do
      {:error, Image.Error.wrap(raw, operation: :thumbnail)}
    end

# `t`

```elixir
@type t() :: %Image.Error{
  __exception__: true,
  message: String.t(),
  operation: atom() | nil,
  path: Path.t() | nil,
  reason: atom() | {atom(), any()} | String.t() | nil,
  value: any() | nil
}
```

A structured `Image.Error`. The `:reason` field is the canonical
discriminator; `:message` is always derivable from `:reason` plus
`:operation`/`:path`/`:value`.

# `wrap`

```elixir
@spec wrap(
  term(),
  keyword()
) :: t()
```

Wraps a raw `{:error, _}` payload from libvips, the colour library,
or another underlying source as an `%Image.Error{}`.

Used at the boundary between Vix and `Image` to attach
high-level context (`:operation`, `:path`, `:value`) before the
error propagates to the caller.

### Arguments

* `raw` is the inner value of the error tuple — typically a
  string from libvips, an atom from `File.*`, or another struct
  that already implements `Exception.message/1`.

* `context` is a keyword list of context fields to attach. The
  accepted keys are `:operation`, `:path`, `:value`, and
  `:reason` (to override the auto-derived reason).

### Examples

    iex> Image.Error.wrap("operation build: bad seek", operation: :open, path: "/tmp/x.jpg")
    %Image.Error{
      reason: "operation build: bad seek",
      operation: :open,
      path: "/tmp/x.jpg",
      message: "open /tmp/x.jpg: operation build: bad seek",
      value: nil
    }

    iex> Image.Error.wrap(:enoent, path: "/tmp/x.jpg")
    %Image.Error{
      reason: :enoent,
      path: "/tmp/x.jpg",
      operation: nil,
      message: "The image file \"/tmp/x.jpg\" was not found or could not be opened",
      value: nil
    }

---

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