Raxol.Core.ErrorHandlingStandard (Raxol v2.0.1)
View SourceStandardized error handling patterns for the Raxol application.
This module defines the standard error handling patterns that should be used consistently across all Raxol modules.
Error Tuple Convention
All functions that can fail should return:
{:ok, result}on success{:error, reason}or{:error, reason, context}on failure
Error Types
Use standardized error atoms:
:invalid_argument- Invalid function arguments:not_found- Resource not found:permission_denied- Insufficient permissions:timeout- Operation timed out:connection_failed- Network/connection error:invalid_state- Invalid state for operation:resource_exhausted- Resource limits exceeded
Pattern Examples
# Basic error handling
def process_data(data) do
with {:ok, validated} <- validate(data),
{:ok, transformed} <- transform(validated),
{:ok, result} <- save(transformed) do
{:ok, result}
else
{:error, _reason} = error ->
Log.error("Failed to process data")
error
end
end
# Error with context
def fetch_user(id) do
case Repo.get(User, id) do
nil -> {:error, :not_found, %{user_id: id}}
user -> {:ok, user}
end
end
Summary
Functions
Aggregates multiple errors into a single error result.
Chains multiple operations that return result tuples.
Ensures a result is returned, converting exceptions to errors.
Flat maps over a result tuple.
Maps over a result tuple, applying a function to the success value.
Converts various error formats to standard error tuples.
Wraps a function that might raise an exception into a result tuple.
Logs and returns the error, useful in pipelines.
Validates required fields in a map or struct.
Provides a default value for error cases.
Retries an operation with exponential backoff.
Types
@type error_result() :: {:error, standard_error()} | {:error, standard_error(), map()}
@type ok_result(type) :: {:ok, type}
@type result(type) :: ok_result(type) | error_result()
@type standard_error() ::
:invalid_argument
| :not_found
| :permission_denied
| :timeout
| :connection_failed
| :invalid_state
| :resource_exhausted
| :internal_error
| :not_implemented
| :conflict
| :precondition_failed
Functions
Aggregates multiple errors into a single error result.
Example
results = [
{:ok, 1},
{:error, :not_found, %{id: 2}},
{:error, :timeout}
]
aggregate_errors(results)
# => {:error, :multiple_errors, %{errors: [...]}}
Chains multiple operations that return result tuples.
Example
chain_operations([
fn -> validate_input(input) end,
fn validated -> process(validated) end,
fn processed -> save(processed) end
])
Ensures a result is returned, converting exceptions to errors.
Example
ensure_result(fn ->
User.get!(123)
end)
# Returns {:ok, user} or {:error, :internal_error, %{...}}
Flat maps over a result tuple.
Example
{:ok, 5}
|> flat_map_ok(fn x -> {:ok, x * 2} end)
# => {:ok, 10}
Maps over a result tuple, applying a function to the success value.
Example
{:ok, 5}
|> map_ok(&(&1 * 2))
# => {:ok, 10}
@spec normalize_error(term()) :: error_result()
Converts various error formats to standard error tuples.
@spec safe_call((-> any()), standard_error()) :: {:ok, any()} | {:error, standard_error(), map()}
Wraps a function that might raise an exception into a result tuple.
Logs and returns the error, useful in pipelines.
Example
{:error, :not_found, %{id: 123}}
|> tap_error("User lookup failed")
# Logs: "User lookup failed: {:error, :not_found, %{id: 123}}"
# Returns: {:error, :not_found, %{id: 123}}
Validates required fields in a map or struct.
Example
validate_required(%{name: "John"}, [:name, :email])
# => {:error, :invalid_argument, %{missing_fields: [:email]}}
Provides a default value for error cases.
Example
{:error, :not_found}
|> with_default("default")
# => "default"
Retries an operation with exponential backoff.
Options
:max_attempts- Maximum number of attempts (default: 3):initial_delay- Initial delay in ms (default: 100):max_delay- Maximum delay in ms (default: 5000):jitter- Add random jitter to delay (default: true)