Ramal.Error exception (Ramal v0.2.0)

Copy Markdown View Source

The error every Ramal function returns as {:error, %Ramal.Error{}}.

When a Ramal error is raised inside an Ash action (for example a bulk action inside a branch), Ash returns it in the errors of an Ash.Error.Invalid; find/2 pulls it out.

reason is an atom from the closed list below, so a host can match on it. message says what happened in words a developer can act on. details carries the data behind the message, for example the stale rows.

reasonmeaning
:not_foundno branch with that id, in memory or in storage
:not_openthe branch is not in the status the call needs: open for run/2, fork/2, merge/2 and propose/2, proposed for approve/2 and reject/2
:stalethe base moved under rows the branch read (details.rows)
:merge_faileda replayed action failed; details has index, type, resource, action and the Ash error
:database_generated_keya branch cannot create a row whose primary key the database generates
:bulk_unsupporteda bulk create, update or destroy inside a branch
:upsert_unsupportedan upsert inside a branch
:multitenancy_unsupporteda multitenant resource used with a tenant inside a branch
:branch_too_largethe branch process exceeded max_heap_size and was stopped
:no_branchable_resourcesthe domain has no resource that opted in with Ramal.Resource
:nested_branchRamal.run/2 was called inside another Ramal.run/2, or Ramal.merge/2 inside one
:missing_snapshotan overlay entry that needs the base row as first seen has none recorded
:limit_reachedRamal.branch/2 or Ramal.fork/2 was refused by :max_active_branches or :branch_rate of Ramal.Supervisor (details.limit, max, and active or window)
:storagethe storage backend failed

Example

iex> error = Ramal.Error.new(:not_open, "branch b1 is already merged", %{status: :merged})
iex> {error.reason, error.message, error.details}
{:not_open, "branch b1 is already merged", %{status: :merged}}
iex> Exception.message(error)
"branch b1 is already merged"

Summary

Functions

Create an Elixir.Ramal.Error without raising it.

The first Ramal.Error in an error Ash returned, or nil.

Types

reason()

@type reason() ::
  :not_found
  | :not_open
  | :stale
  | :merge_failed
  | :database_generated_key
  | :bulk_unsupported
  | :upsert_unsupported
  | :multitenancy_unsupported
  | :branch_too_large
  | :no_branchable_resources
  | :nested_branch
  | :missing_snapshot
  | :limit_reached
  | :storage

t()

@type t() :: %Ramal.Error{
  __exception__: true,
  bread_crumbs: term(),
  class: term(),
  details: map(),
  message: String.t(),
  path: term(),
  reason: reason(),
  splode: term(),
  stacktrace: term(),
  vars: term()
}

Functions

exception(msg)

@spec exception(opts :: Keyword.t()) :: %Ramal.Error{
  __exception__: true,
  bread_crumbs: term(),
  class: term(),
  details: term(),
  message: term(),
  path: term(),
  reason: term(),
  splode: term(),
  stacktrace: term(),
  vars: term()
}

Create an Elixir.Ramal.Error without raising it.

Keys

  • :reason
  • :message
  • :details

find(error)

@spec find(term()) :: t() | nil

The first Ramal.Error in an error Ash returned, or nil.

Ash wraps the errors of an action in an error class (Ash.Error.Invalid and friends) whose errors list holds them. This looks through that list, so a host can match on the reason without knowing how Ash nested it.

Example

iex> error = Ramal.Error.new(:bulk_unsupported, "no bulk inside a branch")
iex> Ramal.Error.find(Ash.Error.to_error_class(error)).reason
:bulk_unsupported
iex> Ramal.Error.find(Ash.Error.to_error_class("something else"))
nil

new(reason, message, details \\ %{})

@spec new(reason(), String.t(), map()) :: t()

Builds an error.

Example

iex> Ramal.Error.new(:not_found, "no branch with id \"b1\"").reason
:not_found