Skip to main content
Structured exceptions tell you what failed, whether to retry, and which agent or run was involved — without parsing raw tracebacks.
from praisonaiagents import Agent, PraisonAIError

agent = Agent(name="assistant", instructions="Be helpful")

try:
    print(agent.start("Say hello in one sentence."))
except PraisonAIError as e:
    print(f"{e.error_category}: {e.message} (agent={e.agent_id}, run={e.run_id})")
The user runs the agent; failures raise typed PraisonAIError with category, message, and run context for recovery.

Quick Start

1

Catch any agent error

from praisonaiagents import Agent, PraisonAIError

agent = Agent(name="assistant", instructions="Be helpful")

try:
    result = agent.start("Say hello in one sentence.")
    print(result)
except PraisonAIError as e:
    print(f"{e.error_category}: {e.message} (agent={e.agent_id}, run={e.run_id})")
2

Handle tool errors specifically

from praisonaiagents import Agent, tool, ToolExecutionError

@tool
def divide(a: float, b: float) -> float:
    """Divide two numbers."""
    return a / b

agent = Agent(instructions="Use divide.", tools=[divide])

try:
    agent.start("Divide 10 by 0.")
except ToolExecutionError as e:
    print(f"Tool {e.tool_name} failed: {e.message}")
    print(f"Retryable: {e.is_retryable}")

How It Works

Every structured error carries message, agent_id, run_id, error_category, and is_retryable. Subclasses add domain fields such as tool_name or model_name.
ClassWhen raisedKey fieldsDefault retryable
PraisonAIErrorBase — catch-allerror_category, contextFalse
ToolExecutionErrorTool fails or loop-guard HALTtool_nameTrue
LLMErrorChat completion failsmodel_nameFalse
ValidationErrorInvalid config or inputfield_nameFalse
NetworkErrorExternal service unreachableservice_name, status_codeTrue
error_category uses typed kinds such as rate_limit, auth, context_overflow, and billing.

Common Patterns

Retry on transient network failures, fail on config bugs:
from praisonaiagents import Agent, NetworkError, ValidationError

agent = Agent(name="assistant")

for attempt in range(3):
    try:
        print(agent.start("Summarise today's news."))
        break
    except NetworkError:
        if attempt == 2:
            raise
    except ValidationError:
        raise  # fix config — retry won't help
Raised errors stop the run; some callbacks record failures on the output instead. See Non-Fatal Errors.

Reaching the Step Limit

When the tool-calling loop reaches ExecutionConfig.max_steps (or max_iter when max_steps is unset), the agent does not hard-cut. On the final permitted step it injects a graceful wrap-up instruction, so the model returns a real summary of what it accomplished and what remains — not a placeholder. Detect truncation with agent.last_stop_reason instead of string-matching:
from praisonaiagents import Agent, ExecutionConfig

agent = Agent(
    name="coder",
    instructions="You are a coding assistant.",
    execution=ExecutionConfig(max_steps=50),
)
result = agent.start("Refactor the auth module across all files")

if agent.last_stop_reason == "max_steps":
    result = agent.start("Continue from where you left off.")

Step Budget

Cap tool-use steps and detect graceful truncation with last_stop_reason

Best Practices

Use ToolExecutionError when you only care about tool failures; reserve PraisonAIError for top-level logging.
Include e.error_category, e.agent_id, and e.run_id in observability hooks — they correlate across multi-agent runs.
Validation failures usually mean a programming or config bug. Fix the root cause instead of retrying blindly.
Loop-guard HALT raises ToolExecutionError. Combine with Loop Guard when tools may repeat indefinitely.

Loop Guard

Stop runaway tool loops with HALT/WARN/BLOCK

Non-Fatal Errors

Callback failures captured without crashing