Agentic operations can fail due to factors outside your code — infrastructure issues, network problems, or service limitations. These operational errors originate from the platform or external services, not from your application logic or the agent’s decisions.Common operational errors include:
Inference errors: When the underlying model fails to respond
The platform handles most operational errors automatically. Agentica employs retry strategies with exponential backoff and jitter for transient failures like inference rate limits, temporary network issues, and service unavailability.You only see errors that are unrecoverable at the platform level. When an error bubbles up to your code, it means the platform has exhausted its retry attempts and the operation cannot be completed without intervention. This design keeps your error handling focused on genuinely exceptional situations.For errors that do reach your code, you should handle them as you would for any other async network operation — with try/catch blocks, additional retry logic if appropriate, and fallback strategies.Some of these errors may represent limitations or bugs in Agentica itself, please see Reporting Bugs for information about how to report such bugs to us.
Agentica exports a comprehensive set of error classes to help you handle different failure scenarios. All errors inherit from AgenticaError, making it easy to catch all SDK-related errors.
All operational errors inherit from AgenticaError. Errors not intentionally raised by the agent may be caught as exceptions inheriting from this base class, which is exported by the SDK under agentica.errors@symbolica/agentica/errors.
Complete Error Reference
All errors inherit from AgenticaError. The hierarchy organizes errors by their source: connection issues, agent invocation problems, or errors from the inference service.
The MaxTokensError occurs when a response exceeds the maximum token limit. You can proactively control this by setting max_tokensmaxTokens when creating agents or agentic functions. Note that this limit applies per inference request — a single agent or agentic function invocation may make multiple inference requests, and each request is subject to this limit independently.
Copy
from agentica import spawn, agentic, MaxTokens# For agentsagent = await spawn( premise="You are a concise assistant.", max_tokens=500 # Limit each invocation to total 500 output tokens)# For agentic functions@agentic(max_tokens=1000)async def summarize(text: str) -> str: """Create a brief summary.""" ...# For finer control, use MaxTokensagent = await spawn( premise="You are a concise assistant.", max_tokens=MaxTokens(per_invocation=5000, per_round=1000, rounds=5))
Error prevention: Avoid unexpectedly long responses in a single inference request
When you set max_tokensmaxTokens, each inference request will stop generating when it reaches that limit. If the natural response would exceed this limit, a MaxTokensError will be raised, which you can catch and handle appropriately (see examples below).
Setting appropriate token limits upfront is more efficient than handling MaxTokensError after the fact, as it prevents wasted compute on overly long responses.
You can catch specific error types to implement different handling strategies. The error hierarchy lets you handle errors at different levels of granularity:
Copy
from agentica import agenticfrom agentica.errors import ( AgenticaError, RateLimitError, InferenceError, ConnectionError, MaxTokensError,)@agentic()async def analyze_text(text: str) -> dict: """Analyze the sentiment and extract key topics.""" ...try: result = await analyze_text(document)except RateLimitError as e: # Handle specific inference error logger.warning(f"Rate limited: {e}") time.sleep(60) result = await analyze_text(document)except MaxTokensError as e: # Handle token limit from inference service logger.warning(f"Response too long: {e}") result = await analyze_text(document[:len(document)//2]) # Try with less inputexcept InferenceError as e: # Catch all other inference service errors (API errors, timeouts, etc.) logger.error(f"Inference service error: {e}") result = {"sentiment": "neutral", "topics": []}except ConnectionError as e: # Handle connection failures logger.error(f"Connection failed: {e}") result = retry_with_backoff(lambda: analyze_text(document))except AgenticaError as e: # Catch any other SDK errors logger.error(f"Unexpected Agentica error: {e}") raise
The platform already retries most failures automatically using exponential backoff and jitter. When an error reaches your code, it means the platform’s built-in retry logic has been exhausted. You typically don’t need additional retry logic, but you may add it for application-specific requirements.
If you need additional retry logic beyond what the platform provides (for example, for application-specific error handling or longer retry windows), you can implement your own retry strategy.You could implement a simple retry strategy like this:
Copy
def retry(operation: Callable, retries: int = 3) -> Any: error = None for _ in range(retries): try: return operation() except Exception as e: error = e raise error
which may be used to wrap any agentic function or agent call:
Copy
result = retry(lambda: extract_date(document), retries=3)
Since agentic functions are just functions already, you may also use widely available libraries such as tenacityts-retry-promise to handle logic for retries.
Copy
from tenacity import retry, stop_after_attempt@retry(stop=stop_after_attempt(3))@agentic()async def process_data(input_data: str) -> dict: """Process and analyze the input data.""" ...
Remember that the platform has already retried transient failures before an error reaches your code. If an operation consistently fails even with your own additional retry logic, consider adjusting your prompts, providing more context, or choosing a different model rather than increasing retry attempts.
Once you get successful results, consider caching them. After retries produce a good response, you can cache it for future calls with the same inputs. This combines resilience with performance. See Caching for strategies.
Proper logging of agentic operations helps you monitor reliability, debug failures, and identify patterns in errors. Log enough context to diagnose issues, but be mindful of sensitive data.
Log agent failures with structured data that includes the operation, error type, and relevant context. This example shows agent-driven test generation with comprehensive logging:
When using fallback strategies, log which tier succeeded. Frequent fallbacks suggest reviewing your approach — consider trying a different model better suited to the task, refining your prompts, or providing additional context.This example shows agentic code review with quality tracking:
Copy
from agentica import agenticfrom dataclasses import dataclass@dataclassclass ReviewResult: issues: list[str] severity: str suggestions: list[str]@agentic()async def deep_code_review(code: str, context: dict) -> ReviewResult: """ Perform comprehensive code review including: - Security vulnerabilities - Performance issues - Best practices violations - Design pattern suggestions Analyze with full codebase context. """ ...@agentic()async def basic_code_review(code: str) -> ReviewResult: """ Perform basic code review: - Syntax issues - Common anti-patterns - Simple style violations No codebase context required. """ ...async def review_code_with_monitoring(code: str, context: dict = None) -> ReviewResult: # Try comprehensive review with context if context: try: result = await deep_code_review(code, context) logger.info("Code review completed", extra={ "method": "deep_review", "issues_found": len(result.issues), "severity": result.severity }) return result except Exception as e: logger.warning("Deep review failed, falling back to basic", extra={ "error": str(e), "code_length": len(code) }) # Fallback to basic review try: result = await basic_code_review(code) logger.warning("Code review completed with basic analysis only", extra={ "method": "basic_review", "issues_found": len(result.issues), "severity": result.severity }) return result except Exception as e: logger.error("All review methods failed", extra={ "error": str(e), "code_length": len(code) }) raise
Use metrics from these logs to track fallback rates and identify patterns. High fallback rates are a useful diagnostic — they suggest opportunities to choose a model better suited to your task, refine your prompts, or provide additional context.
When rate limits from providers are imposed, exponential backoff is employed with sensible defaults in a blocking fashion.
The initial delay is multiplied by a factor of exponential_base * (1 + jitter * random_float) with every retry till max_retries is reached, where 0.0 <= random_float < 1.0.