Jido.Error (Jido v2.4.0)

Copy Markdown View Source

Unified error handling for the Jido ecosystem using Splode.

Error Types

Six consolidated error types cover all failure scenarios:

ErrorUse Case
ValidationErrorInvalid inputs, actions, sensors, configs
ExecutionErrorRuntime failures during execution or planning
RoutingErrorSignal routing and dispatch failures
TimeoutErrorOperation timeouts
CompensationErrorSaga compensation failures
InternalErrorUnexpected system failures

Usage

# Validation failures (with optional kind)
Jido.Error.validation_error("Invalid email", kind: :input, field: :email)
Jido.Error.validation_error("Unknown action", kind: :action, action: MyAction)

# Execution failures (with optional phase)
Jido.Error.execution_error("Action failed", phase: :run)
Jido.Error.execution_error("Planning failed", phase: :planning)

# Routing/dispatch failures
Jido.Error.routing_error("No handler", target: "user.created")

# Timeouts
Jido.Error.timeout_error("Timed out", timeout: 5000)

# Internal errors
Jido.Error.internal_error("Unexpected failure")

Splode Error Classes

Errors are classified for aggregation (in order of precedence):

  • :invalid - Validation failures
  • :execution - Runtime failures
  • :routing - Routing/dispatch failures
  • :timeout - Timeouts
  • :internal - Unexpected failures

Summary

Functions

Creates a compensation error.

Creates an execution error.

Extracts the message string from a nested error structure.

Formats a NimbleOptions configuration error.

Formats a NimbleOptions validation error for parameters.

Creates an internal error.

Returns whether an error is safe to retry by default.

Creates a routing error.

Creates a timeout error.

Converts an error into a stable, public map.

Traverses errors, calling fun for each leaf error, and returns a nested map of results grouped by each error's path.

Raises an error if the result is an error, otherwise returns the result

Creates a validation error.

Types

class()

@type class() :: %{
  :__struct__ => class_module(),
  :__exception__ => true,
  :errors => [t()],
  :class => error_class(),
  :bread_crumbs => [String.t()],
  :vars => Keyword.t(),
  :stacktrace => Splode.Stacktrace.t() | nil,
  :context => map(),
  optional(atom()) => any()
}

class_module()

@type class_module() ::
  Jido.Error.Internal
  | Jido.Error.Timeout
  | Jido.Error.Routing
  | Jido.Error.Execution
  | Jido.Error.Invalid
  | Splode.Error.Unknown

error_class()

@type error_class() ::
  :internal | :timeout | :routing | :execution | :invalid | :unknown

t()

@type t() :: %{
  :__struct__ => module(),
  :__exception__ => true,
  :class => error_class(),
  :bread_crumbs => [String.t()],
  :vars => Keyword.t(),
  :stacktrace => Splode.Stacktrace.t() | nil,
  :context => map(),
  optional(atom()) => any()
}

Functions

compensation_error(message, opts \\ [])

@spec compensation_error(String.t(), keyword() | map()) ::
  Jido.Error.CompensationError.t()

Creates a compensation error.

Options

  • :original_error - The error that triggered compensation
  • :compensated - Whether compensation succeeded (default: false)
  • :result - Result from successful compensation
  • :details - Additional context map

execution_error(message, opts \\ [])

@spec execution_error(String.t(), keyword() | map()) :: Jido.Error.ExecutionError.t()

Creates an execution error.

Options

  • :phase - Where failure occurred: :execution, :planning
  • :details - Additional context map
  • Any other keys are merged into details

extract_message(error)

@spec extract_message(any()) :: String.t()

Extracts the message string from a nested error structure.

format_nimble_config_error(error, module_type, module)

@spec format_nimble_config_error(any(), String.t(), module()) :: String.t()

Formats a NimbleOptions configuration error.

format_nimble_validation_error(error, module_type, module)

@spec format_nimble_validation_error(any(), String.t(), module()) :: String.t()

Formats a NimbleOptions validation error for parameters.

internal_error(message, opts \\ [])

@spec internal_error(String.t(), keyword() | map()) :: Jido.Error.InternalError.t()

Creates an internal error.

Options

  • :details - Additional context map

retryable?(error)

@spec retryable?(term()) :: boolean()

Returns whether an error is safe to retry by default.

Explicit :retry, :retryable, and :retryable? boolean hints in structured details override the default classification.

routing_error(message, opts \\ [])

@spec routing_error(String.t(), keyword() | map()) :: Jido.Error.RoutingError.t()

Creates a routing error.

Options

  • :target - The intended routing target
  • :details - Additional context map

splode_error?(arg1, splode)

timeout_error(message, opts \\ [])

@spec timeout_error(String.t(), keyword() | map()) :: Jido.Error.TimeoutError.t()

Creates a timeout error.

Options

  • :timeout - The timeout value in milliseconds
  • :details - Additional context map

to_map(error)

@spec to_map(any()) :: map()

Converts an error into a stable, public map.

The returned map is suitable for transport and reporting boundaries. It includes bounded, sanitized details and never includes stacktraces by default.

Details traverse at most 4 container levels, with up to 20 entries per map or list. Scalar leaves are kept at the depth limit, so validation paths retain field names and list indexes. Strings are limited to 512 characters plus a truncation suffix. Invalid UTF-8 binaries use bounded inspection. Deeper containers and opaque terms are replaced with [DEPTH_LIMIT].

traverse_errors(error_or_errors, fun)

Traverses errors, calling fun for each leaf error, and returns a nested map of results grouped by each error's path.

See Splode.traverse_errors/2 for full documentation.

Example

iex> Elixir.Jido.Error.traverse_errors(error, fn error ->
...>   Exception.message(error)
...> end)
%{name: ["name is required"]}

unwrap!(result, opts \\ nil)

Raises an error if the result is an error, otherwise returns the result

Alternatively, you can use the defsplode macro, which does this automatically.

Options

  • :error_opts - Options to pass to to_error/2 when converting the returned error
  • :unknown_error_opts - Options to pass to the unknown error if the function returns only :error. not necessary if your function always returns {:error, error}.

Examples

def function(arg) do

case do_something(arg) do
  :success -> :ok
  {:success, result} -> {:ok, result}
  {:error, error} -> {:error, error}
end

end

def function!(arg) do

YourErrors.unwrap!(function(arg))

end

validation_error(message, opts \\ [])

@spec validation_error(String.t(), keyword() | map()) ::
  Jido.Error.ValidationError.t()

Creates a validation error.

Options

  • :kind - Category: :input, :action, :sensor, :config, :state_size
  • :subject - The invalid value
  • :field - Alias for :subject (for input validation)
  • :action - Alias for :subject with kind: :action
  • :sensor - Alias for :subject with kind: :sensor
  • :details - Additional context map

Examples

validation_error("Invalid email", field: :email)
validation_error("Unknown action", kind: :action, subject: MyAction)