# `VFS.Error`
[🔗](https://github.com/ivarvong/vfs/blob/v0.1.0/lib/vfs/error.ex#L1)

Structured error returned by every fallible `VFS.Mountable` op.

## Fields

  * `:kind`    — atom from the `kind/0` type. The primary control-flow value;
    pattern-match on this.
  * `:path`    — the path that failed, as the *user* expressed it (before
    mount-prefix stripping). May be `nil` for ops that don't take a path.
  * `:mount`   — the mountpoint that handled the op, if any. Useful for
    log context in mount-table dispatch.
  * `:message` — human-readable; defaults to a sensible string built from
    the other fields.

## Examples

    iex> {:error, err} = VFS.read_file(VFS.new(), "/nope")
    iex> err.kind
    :enoent

Raisable for `!`-style helpers:

    iex> raise VFS.Error, kind: :enoent, path: "/foo"
    ** (VFS.Error) :enoent at /foo

# `kind`

```elixir
@type kind() ::
  :enoent
  | :eexist
  | :eisdir
  | :enotdir
  | :erofs
  | :enotsup
  | :eacces
  | :einval
  | :exdev
  | :eio
  | :eloop
```

POSIX-style error kinds, kept tight on purpose. Pattern match on these
for flow control.

  * `:enoent`   — path doesn't exist
  * `:eexist`   — path already exists (e.g. `mkdir` collision)
  * `:eisdir`   — expected a file, got a directory
  * `:enotdir`  — expected a directory, got a file
  * `:erofs`    — the mount or wrapper is read-only
  * `:enotsup`  — the backend doesn't support this op
  * `:eacces`   — permission denied
  * `:einval`   — bad argument (e.g. malformed path or option)
  * `:exdev`    — cross-mount op that can't be atomic
  * `:eio`      — underlying I/O failure
  * `:eloop`    — symlink loop

# `t`

```elixir
@type t() :: %VFS.Error{
  __exception__: true,
  kind: kind(),
  message: String.t() | nil,
  mount: String.t() | nil,
  path: String.t() | nil
}
```

# `new`

```elixir
@spec new(
  kind(),
  keyword()
) :: t()
```

Build an error struct without raising. Convenience constructor for
backends and the mount-table dispatcher.

# `put_mount`

```elixir
@spec put_mount(t(), String.t()) :: t()
```

Add or overwrite the `:mount` field on an existing error. Used by the
mount-table dispatcher to attach mount context to errors bubbled up
from leaf backends.

# `put_path`

```elixir
@spec put_path(t(), String.t()) :: t()
```

Rewrite the `:path` field on an existing error, regenerating the
default message to match. Used by the mount-table dispatcher: backends
report paths in their own namespace (mount prefix stripped), and the
dispatcher rewrites them into the user's namespace — the
human-readable message must follow, or logs name a path that does not
exist in the user's view.

A custom message (one the backend set explicitly) is preserved.

## Examples

    iex> err = VFS.Error.new(:enoent, path: "/x") |> VFS.Error.put_path("/repo/x")
    iex> Exception.message(err)
    ":enoent at /repo/x"

    iex> err = VFS.Error.new(:eio, path: "/x", message: "disk on fire")
    iex> VFS.Error.put_path(err, "/repo/x").message
    "disk on fire"

---

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