How to Handle Errors with Custom Error Policies in Jido AgentServer
Jido AgentServer delegates all error directives to Jido.AgentServer.ErrorPolicy.handle/2, which executes either built-in policies (:log_only, :stop_on_error, {:emit_signal, cfg}, {:max_errors, n}) or custom functions that return {:ok, state} or {:stop, reason, state}.
Handling runtime failures gracefully is critical for production agent systems. In the Jido framework, the AgentServer isolates all side-effects—including error handling—inside a GenServer process. When an agent action fails, the system generates a Jido.Agent.Directive.Error that must be processed according to a configurable error policy. This article explains how to leverage built-in policies and implement custom error handlers to control exactly how your Jido agents respond to failures.
Understanding Jido AgentServer Error Handling Architecture
Error handling in Jido AgentServer follows a delegation pattern. When the directive executor encounters an error directive, it immediately forwards the directive to Jido.AgentServer.ErrorPolicy.handle/2 along with the current server state.
According to the source code in [lib/jido/agent_server/error_policy.ex](https://github.com/agentjido/jido/blob/main/lib/jido/agent_server/error_policy.ex), the handle/2 function pattern-matches on state.error_policy to determine the appropriate response. The policy value is validated at startup by Jido.AgentServer.Options.validate_error_policy/1 in [lib/jido/agent_server/options.ex](https://github.com/agentjido/jido/blob/main/lib/jido/agent_server/options.ex) and stored in the runtime state defined in [lib/jido/agent_server/state.ex](https://github.com/agentjido/jido/blob/main/lib/jido/agent_server/state.ex).
Built-in Error Policies in Jido AgentServer
Jido provides five built-in policy variants that cover common error handling scenarios without requiring custom code.
Log Only Policy (:log_only)
The default policy simply logs the error and continues execution. This is the safest option for development and non-critical production agents.
Jido.AgentServer.start(
agent: MyAgent,
id: "my_agent",
error_policy: :log_only
)
Under the hood, ErrorPolicy.handle/2 calls log_error/3 and returns {:ok, state}, allowing the GenServer to continue processing subsequent directives.
Stop on Error Policy (:stop_on_error)
For critical agents where any failure should halt processing immediately, use the :stop_on_error policy.
Jido.AgentServer.start(
agent: MyAgent,
id: "critical_agent",
error_policy: :stop_on_error
)
When triggered, this policy logs the error and returns {:stop, {:agent_error, error}, state}, causing the AgentServer GenServer to terminate with the error reason.
Emit Signal Policy ({:emit_signal, dispatch_cfg})
This policy converts errors into Jido signals that can be consumed by other agents or external systems. It accepts a dispatch configuration map.
dispatch_cfg = %{topic: "agent.errors", qos: 1}
Jido.AgentServer.start(
agent: MyAgent,
id: "signaling_agent",
error_policy: {:emit_signal, dispatch_cfg}
)
The implementation in error_policy.ex uses build_error_signal/3 to construct a Jido.Signal with type "jido.agent.error", then dispatches it asynchronously via emit_error_signal/4.
Max Errors Policy ({:max_errors, n})
Use this policy to implement circuit-breaker-like behavior, allowing a specific number of errors before stopping the agent.
Jido.AgentServer.start(
agent: MyAgent,
id: "resilient_agent",
error_policy: {:max_errors, 5}
)
This policy increments state.error_count using State.increment_error_count/1. If the count reaches the threshold, it stops the agent; otherwise, it logs a warning and continues.
Creating Custom Error Policies in Jido AgentServer
When built-in policies are insufficient, you can provide a custom function that implements the ErrorPolicy contract.
Function Signature and Return Contract
The custom function must match this type specification:
@type result :: {:ok, State.t()} | {:stop, term(), State.t()}
@spec handle(ErrorDirective.t(), State.t()) :: result()
The function receives:
%Jido.Agent.Directive.Error{error: term(), context: term() | nil}— the error directive containing the failure details and optional context%Jido.AgentServer.State{}— the current server state
Safety Guarantees
According to the source in error_policy.ex, custom functions execute inside a try … rescue … catch block. If your function raises an exception, returns an unexpected value, or throws an error, the policy handler catches it, logs the failure, and returns {:ok, state} to keep the agent alive. This sandboxing prevents misbehaving custom policies from crashing the entire AgentServer.
Example: Custom Monitoring Integration
Here is a complete example that reports errors to an external monitoring service while maintaining local error metrics:
defmodule MyApp.CustomErrorPolicy do
alias Jido.AgentServer.State
def handle(%Jido.Agent.Directive.Error{error: err, context: ctx}, state) do
# Report to external monitoring
MyMonitoringService.report_error(
agent_id: state.id,
error: err,
context: ctx,
timestamp: DateTime.utc_now()
)
# Update custom metrics in state
new_state = %State{
state |
custom_error_count: (state.custom_error_count || 0) + 1,
last_error_at: DateTime.utc_now()
}
# Decide whether to continue or stop based on error severity
if critical_error?(err) do
{:stop, {:critical_error, err}, new_state}
else
{:ok, new_state}
end
end
defp critical_error?(%MyApp.CriticalException{}), do: true
defp critical_error?(_), do: false
end
# Usage when starting the server
Jido.AgentServer.start(
agent: MyAgent,
id: "monitored_agent",
error_policy: &MyApp.CustomErrorPolicy.handle/2
)
Configuring Error Policies at Startup
The error_policy option is validated during server initialization. You can configure it via the Jido.AgentServer.start/1 function or through your application supervisor.
# Using a built-in atom policy
Jido.AgentServer.start(
agent: MyAgent,
id: "simple_agent",
error_policy: :stop_on_error
)
# Using a tuple policy with configuration
Jido.AgentServer.start(
agent: MyAgent,
id: "circuit_breaker_agent",
error_policy: {:max_errors, 10}
)
# Using a custom function (captured or anonymous)
custom_fn = fn error, state ->
# Custom logic here
{:ok, state}
end
Jido.AgentServer.start(
agent: MyAgent,
id: "custom_agent",
error_policy: custom_fn
)
The validation logic in Jido.AgentServer.Options.validate_error_policy/1 ensures that only valid policy shapes are accepted at runtime, preventing configuration errors from causing failures later during error handling.
Key Source Files and Implementation Details
Understanding the source structure helps when debugging error policy behavior or extending functionality:
Summary
- Jido AgentServer delegates all error handling to the
Jido.AgentServer.ErrorPolicymodule via thehandle/2function. - Configure error behavior at startup using the
error_policyoption, validated byJido.AgentServer.Options.validate_error_policy/1. - Choose from built-in policies:
:log_only(default),:stop_on_error,{:emit_signal, config}, or{:max_errors, n}. - Implement custom policies by providing a function that accepts an
Errordirective andState, returning either{:ok, state}or{:stop, reason, state}. - Custom functions execute inside a sandboxed
try/rescue/catchblock to prevent crashes from destabilizing the AgentServer.
Frequently Asked Questions
What is the default error policy in Jido AgentServer?
The default error policy is :log_only. When an error directive occurs, the server logs the error details and returns {:ok, state}, allowing the agent to continue processing subsequent directives without interruption. This policy is set automatically if you do not specify an error_policy option when starting the server.
How do I stop a Jido AgentServer after a specific number of errors?
Use the {:max_errors, n} tuple policy, where n is the error threshold. The server maintains an internal error_count in its state (incremented via State.increment_error_count/1). Once the count reaches n, the agent stops with reason {:max_errors_reached, n}. Below the threshold, it logs warnings and continues.
Jido.AgentServer.start(
agent: MyAgent,
id: "circuit_breaker",
error_policy: {:max_errors, 5}
)
Can I integrate external monitoring tools with Jido AgentServer error handling?
Yes, by providing a custom error policy function. The function receives the %Jido.Agent.Directive.Error{} struct and the current %Jido.AgentServer.State{}, allowing you to extract error details, agent IDs, and context. You can then call external APIs (e.g., Sentry, Datadog, or custom webhooks) before returning {:ok, state} or {:stop, reason, state}. The function executes inside a protected sandbox, so exceptions in your monitoring code won't crash the agent.
What happens if my custom error policy function crashes or returns an invalid value?
The ErrorPolicy.handle/2 function wraps custom function execution in a try … rescue … catch block. If your function raises an exception, returns a value other than {:ok, state} or {:stop, reason, state}, or throws an error, the policy handler catches the failure, logs an appropriate message, and returns {:ok, state}. This safety mechanism ensures that a buggy custom policy cannot inadvertently terminate the AgentServer or leave it in an inconsistent state.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →