Skip to main content

Error Codes Reference

All AgentFlow exceptions use structured error codes for programmatic handling and observability.

Exception Hierarchy


Graph Errors

GRAPH_000 — Generic Graph Error

Base error code for general graph operations.

FieldValue
CodeGRAPH_000
RetryableNo
CategoryGraph

Raised by: Any graph operation failure.

Example:

from agentflow.core.exceptions import GraphError

raise GraphError(
message="Graph failed to initialize",
error_code="GRAPH_000",
context={"graph_name": "my_agent"}
)

Common causes:

  • Invalid graph configuration
  • Node initialization failure
  • Edge routing error

GRAPH_001+ — Extended Graph Errors

Extended error codes for specific graph failures.

FieldValue
CodesGRAPH_001, GRAPH_002, etc.
RetryableNo
CategoryGraph

Node Errors

NODE_000 — Generic Node Error

Base error code for node-specific errors.

FieldValue
CodeNODE_000
RetryableDepends on cause
CategoryGraph / Node

Raised by: Node execution failures.

Example:

from agentflow.core.exceptions import NodeError

raise NodeError(
message="Node execution failed",
error_code="NODE_000",
context={"node_name": "process_data", "input_size": 100}
)

Common causes:

  • Tool execution failure
  • Invalid node input
  • Node timeout
  • Node resource exhaustion

NODE_001+ — Extended Node Errors

Extended error codes for specific node failures.

FieldValue
CodesNODE_001, NODE_002, etc.
RetryableDepends on cause

NODE_TIMEOUT_000 — Node or Tool Timeout

A node or a tool call exceeded its allotted execution time.

FieldValue
CodeNODE_TIMEOUT_000 (default), NODE_TIMEOUT_001 and above for specific cases
RetryableSometimes (a transient hang is; a genuinely slow operation is not)
CategoryNode
Base classNodeError
from agentflow.core.exceptions import NodeTimeoutError

Without a deadline, a node that hangs on a half-open socket or an unresponsive MCP server blocks the graph forever: the loop never advances a step, so the recursion limit never trips and the between-nodes stop check is never reached. Timing the call out converts an indefinite hang into a normal node error the execution loop can persist, report, and recover from.

Common causes:

  • A custom tool that never returns
  • An unresponsive MCP server
  • A node deliberately doing work longer than the 900s default

Fix: Raise the relevant deadline through the node_timeout or tool_timeout run-config key, or fix the hanging call. Pass None or 0 to disable a deadline entirely. See the graph reference.


Recursion Errors

RECURSION_000 — Recursion Limit Exceeded

Raised when graph execution exceeds the configured recursion limit.

FieldValue
CodeRECURSION_000
RetryableNo (requires config change)
CategoryGraph

Example:

from agentflow.core.exceptions import GraphRecursionError

raise GraphRecursionError(
message="Recursion limit exceeded in graph execution",
error_code="RECURSION_000",
context={"recursion_depth": 100, "max_depth": 50}
)

Common causes:

  • Infinite loop in graph routing
  • Tool repeatedly calling itself
  • Missing termination condition
  • Tool selection cycling

Fix: Check your graph for loops, add recursion limits, or increase recursion_limit in config.


Storage Errors

STORAGE_000 — Generic Storage Error

Base error code for storage layer errors.

FieldValue
CodeSTORAGE_000
RetryableNo
CategoryStorage

Raised by: General storage operation failures.


STORAGE_TRANSIENT_000 — Transient Storage Error

Temporary storage failures that may succeed on retry.

FieldValue
CodeSTORAGE_TRANSIENT_000
RetryableYes
CategoryStorage

Common causes:

  • Database connection timeout
  • Network interruption
  • Lock contention
  • Temporary resource unavailability

Example:

from agentflow.core.exceptions import TransientStorageError

raise TransientStorageError(
message="Database connection timeout",
error_code="STORAGE_TRANSIENT_000",
context={"operation": "read_thread", "timeout_ms": 5000}
)

Recovery: Implement exponential backoff retry logic.


STORAGE_SERIALIZATION_000 — Serialization Error

Failed to serialize or deserialize data.

FieldValue
CodeSTORAGE_SERIALIZATION_000
RetryableNo (data is corrupt/invalid)
CategoryStorage

Common causes:

  • Invalid state schema
  • Corrupt checkpoint data
  • Incompatible schema version
  • Invalid message format

Example:

from agentflow.core.exceptions import SerializationError

raise SerializationError(
message="Failed to deserialize state",
error_code="STORAGE_SERIALIZATION_000",
context={"thread_id": "abc123", "schema_version": "2"}
)

STORAGE_SCHEMA_000 — Schema Version Error

Schema version detection or migration failed.

FieldValue
CodeSTORAGE_SCHEMA_000
RetryableNo (requires migration)
CategoryStorage

Common causes:

  • Upgrading AgentFlow without running migrations
  • Database schema out of sync with code version
  • Corrupt schema version table

Fix: Run database migrations after upgrading AgentFlow.


STORAGE_NOT_FOUND_000 — Resource Not Found

Requested resource does not exist in storage.

FieldValue
CodeSTORAGE_NOT_FOUND_000
RetryableNo (resource doesn't exist)
CategoryStorage

Common causes:

  • Invalid thread_id
  • Thread was deleted
  • Checkpoint expired
  • Missing required resource

Example:

from agentflow.core.exceptions import ResourceNotFoundError

raise ResourceNotFoundError(
message="Thread not found",
error_code="STORAGE_NOT_FOUND_000",
context={"thread_id": "abc123"}
)

METRICS_000 — Metrics Error

Non-critical metrics emission failure.

FieldValue
CodeMETRICS_000
RetryableNo (metrics are non-critical)
CategoryObservability

Note: This error is typically logged but not raised, as metrics failures should not interrupt operations.


STORAGE_CONFLICT_000 — Stale State

A durable state write lost its optimistic-concurrency check.

FieldValue
CodeSTORAGE_CONFLICT_000 (default), STORAGE_CONFLICT_001 for a version mismatch on write
RetryableYes, after reloading the latest state
CategoryStorage
Base classStorageError
from agentflow.core.exceptions import StaleStateError

The writer based its update on a state version that is no longer current: another execution committed a newer state for the same thread in the meantime. Committing anyway would silently discard that other execution's work, so the write is rejected instead.

Context keys: thread_id, expected_version, current_version.

Common causes:

  • Two requests processing the same thread_id concurrently
  • Several server replicas serving the same thread
  • A retried request racing the original

Fix: Treat it as a conflict (HTTP 409). Reload the latest state and retry the turn rather than overwriting blindly. On conflict the checkpointer invalidates its cache for the thread, so the next read comes from Postgres. See Set up checkpointing.


Control Flow Signals

GraphStopRequested

A stop was requested while a node was still running.

FieldValue
CodeNone (plain Exception subclass, no error code)
RetryableNot applicable
CategoryControl flow
Base classException
from agentflow.core.exceptions import GraphStopRequested

This is control flow, not a failure. The execution loop catches it, marks the run stopped, persists that, and returns normally. It exists because a stop observed during a node cannot be handled by the between-nodes stop check: the node has to be cancelled first, and the loop needs to tell that cancellation apart from a genuine error.

Attributes: node_name — the node that was running when the stop arrived.

Fix: Nothing to fix. Do not catch it in node code or in a broad except Exception around invoke, or you will convert a clean stop into an error.


Media Errors

MEDIA_000 — Unsupported Media Input

Model cannot accept the given media input type.

FieldValue
CodeMEDIA_000 (via exception)
RetryableNo (requires model change)
CategoryMedia

Raised by: UnsupportedMediaInputError

Attributes:

AttributeTypeDescription
providerstringProvider identifier (e.g., "openai", "google")
modelstringModel name (e.g., "gpt-4o", "gemini-1.5-pro")
media_typestringType of media (e.g., "image", "document", "audio")
source_kindstringHow media was provided ("url", "file_id", "data", "internal_ref")
transports_attemptedlistTransport modes tried before failure

Common causes:

  • Model doesn't support vision but image was provided
  • Model doesn't support document input
  • External URL not allowed for provider

Import path: UnsupportedMediaInputError is not re-exported from agentflow.core.exceptions. Import it from its own module:

from agentflow.core.exceptions.media_exceptions import UnsupportedMediaInputError

Example:

from agentflow.core.exceptions.media_exceptions import UnsupportedMediaInputError

raise UnsupportedMediaInputError(
provider="openai",
model="gpt-4o-mini",
media_type="image",
source_kind="url",
transports_attempted=["inline", "url"]
)

Fix: Use a vision-capable model (e.g., gpt-4o, gemini-1.5-pro) or remove media inputs.


Validation Errors

VALIDATION_000 — Input Validation Failed

Input validation detected a policy violation.

FieldValue
CodeVALIDATION_000 (via exception)
RetryableNo (input is invalid)
CategorySecurity

Raised by: ValidationError

Attributes:

AttributeTypeDescription
messagestringHuman-readable error message
violation_typestringType of violation
detailsdictAdditional violation details

Common violation types:

Violation TypeDescription
prompt_injectionDirect or indirect prompt injection detected
jailbreakJailbreak attempt detected
content_policyContent policy violation
encoding_attackObfuscation via encoding detected
delimiter_confusionConflicting delimiters in input
payload_splittingAttack distributed across inputs
system_leakAttempt to extract system prompt

Example:

from agentflow.utils.validators import ValidationError

raise ValidationError(
message="Prompt injection detected",
violation_type="prompt_injection",
details={"pattern": "ignore previous instructions"}
)

Fix: Sanitize user input, use input validators, enable strict mode for production.


Error Code Quick Reference

Code PrefixCategoryRetryableBase Class
GRAPH_000+Graph operationsNoGraphError
NODE_000+Node executionDependsNodeError
RECURSION_000Recursion limitsNoGraphRecursionError
NODE_TIMEOUT_000+Node or tool deadline exceededSometimesNodeTimeoutError
STORAGE_000Generic storageNoStorageError
STORAGE_TRANSIENT_000+Retryable storageYesTransientStorageError
STORAGE_SERIALIZATION_000SerializationNoSerializationError
STORAGE_SCHEMA_000Schema/migrationNoSchemaVersionError
STORAGE_NOT_FOUND_000Resource not foundNoResourceNotFoundError
STORAGE_CONFLICT_000+Optimistic concurrency conflictYes, after reloading stateStaleStateError
METRICS_000MetricsNoMetricsError
MEDIA_000Media inputNoUnsupportedMediaInputError
VALIDATION_000ValidationNoValidationError

Structured Error Responses

All AgentFlow errors include a to_dict() method for structured logging and API responses:

try:
await agent.process(message)
except GraphError as e:
error_response = e.to_dict()
# {
# "error_type": "GraphRecursionError",
# "error_code": "RECURSION_000",
# "message": "Recursion limit exceeded",
# "context": {"recursion_depth": 100, "max_depth": 50}
# }

Handling Errors

Basic Error Handling

from agentflow.core.exceptions import (
GraphError,
GraphRecursionError,
StorageError,
TransientStorageError,
)

try:
result = await agent.process(message)
except GraphRecursionError as e:
# Recursion limit exceeded - increase limit or fix loop
print(f"Recursion error: {e.error_code}")
except TransientStorageError as e:
# Retry with backoff
await retry_with_backoff(operation)
except StorageError as e:
# Non-retryable storage error
print(f"Storage error: {e.error_code}")
except GraphError as e:
# Generic graph error
print(f"Graph error: {e.error_code}")

Retry Logic for Transient Errors

import asyncio

async def retry_with_backoff(func, max_retries=3, base_delay=1.0):
for attempt in range(max_retries):
try:
return await func()
except TransientStorageError:
if attempt == max_retries - 1:
raise
delay = base_delay * (2 ** attempt)
await asyncio.sleep(delay)