Overview
The Claude Agent SDK provides a hierarchy of exception types for handling different error conditions.
from claude_agent_sdk import ClaudeSDKError, CLINotFoundError, ProcessError
try:
result = await query("Hello Claude")
except CLINotFoundError as e:
print(f"Claude Code CLI not found: {e}")
except ProcessError as e:
print(f"CLI process failed: {e}")
except ClaudeSDKError as e:
print(f"SDK error: {e}")
Error Hierarchy
ClaudeSDKError (base)
├── CLIConnectionError
│ └── CLINotFoundError
├── ProcessError
├── CLIJSONDecodeError
└── MessageParseError
ClaudeSDKError
Base exception for all Claude SDK errors.
class ClaudeSDKError(Exception):
"""Base exception for all Claude SDK errors."""
Catch this to handle any SDK-related error:
try:
async for message in client:
process_message(message)
except ClaudeSDKError as e:
print(f"SDK error occurred: {e}")
CLIConnectionError
Raised when unable to connect to Claude Code.
class CLIConnectionError(ClaudeSDKError):
"""Raised when unable to connect to Claude Code."""
This is a base class for connection-related errors. Usually you’ll see its subclass CLINotFoundError instead.
CLINotFoundError
Raised when Claude Code CLI is not found or not installed.
class CLINotFoundError(CLIConnectionError):
def __init__(
self,
message: str = "Claude Code not found",
cli_path: str | None = None
)
message
str
default:"Claude Code not found"
Error message.
Path where the CLI was expected, if known.
Example
from claude_agent_sdk import query, CLINotFoundError
try:
result = await query("Hello")
except CLINotFoundError as e:
print(f"Please install Claude Code CLI: {e}")
print("Visit https://docs.anthropic.com/en/docs/claude-code")
Common Causes
- Claude Code CLI not installed
- CLI not in system PATH
- Incorrect
cli_path in ClaudeAgentOptions
Solutions
-
Install Claude Code:
brew install anthropics/claude/claude
-
Specify custom CLI path:
options = ClaudeAgentOptions(cli_path="/custom/path/to/claude")
ProcessError
Raised when the CLI process fails.
class ProcessError(ClaudeSDKError):
def __init__(
self,
message: str,
exit_code: int | None = None,
stderr: str | None = None
)
exit_code: int | None
stderr: str | None
Standard error output from the CLI process.
Example
from claude_agent_sdk import ClaudeSDKClient, ProcessError
try:
client = ClaudeSDKClient()
async for message in client:
process_message(message)
except ProcessError as e:
print(f"CLI process failed with exit code {e.exit_code}")
if e.stderr:
print(f"Error output: {e.stderr}")
Common Causes
- Invalid CLI arguments
- Authentication failures
- API key issues
- Resource exhaustion
- CLI crashes
CLIJSONDecodeError
Raised when unable to decode JSON from CLI output.
class CLIJSONDecodeError(ClaudeSDKError):
def __init__(self, line: str, original_error: Exception)
line: str
original_error: Exception
The line that failed to parse (truncated to 100 chars in message).
The underlying JSON decode exception.
Example
from claude_agent_sdk import ClaudeSDKClient, CLIJSONDecodeError
try:
async for message in client:
process_message(message)
except CLIJSONDecodeError as e:
print(f"Failed to parse CLI output: {e}")
print(f"Original error: {e.original_error}")
print(f"Problematic line: {e.line[:100]}...")
Common Causes
- CLI version mismatch
- Corrupted output
- CLI bug
- Mixing stdout and stderr
Solutions
- Update Claude Code CLI to latest version
- Check for CLI warnings/errors
- Report issue if persistent
MessageParseError
Raised when unable to parse a message from CLI output.
class MessageParseError(ClaudeSDKError):
def __init__(
self,
message: str,
data: dict[str, Any] | None = None
)
data: dict[str, Any] | None
The message data that failed to parse.
Example
from claude_agent_sdk import ClaudeSDKClient, MessageParseError
try:
async for message in client:
process_message(message)
except MessageParseError as e:
print(f"Failed to parse message: {e}")
if e.data:
print(f"Message data: {e.data}")
Common Causes
- Unexpected message format
- SDK version mismatch with CLI
- Missing required fields
- Type validation failures
Error Handling Best Practices
Specific Error Handling
from claude_agent_sdk import (
query,
ClaudeSDKError,
CLINotFoundError,
ProcessError,
CLIJSONDecodeError,
)
try:
result = await query("Analyze this code")
except CLINotFoundError:
print("Please install Claude Code CLI")
except ProcessError as e:
if e.exit_code == 1:
print("Authentication failed - check API key")
else:
print(f"CLI process error: {e}")
except CLIJSONDecodeError as e:
print(f"CLI output parsing failed: {e}")
# Report bug or check CLI version
except ClaudeSDKError as e:
print(f"Unknown SDK error: {e}")
Graceful Degradation
from claude_agent_sdk import ClaudeSDKClient, ClaudeSDKError
async def robust_query(prompt: str, max_retries: int = 3):
for attempt in range(max_retries):
try:
client = ClaudeSDKClient()
async for message in client:
if isinstance(message, ResultMessage):
return message
except CLIJSONDecodeError:
# Transient parsing error, retry
if attempt < max_retries - 1:
await asyncio.sleep(1)
continue
raise
except ProcessError as e:
if e.exit_code == 429: # Rate limit
if attempt < max_retries - 1:
await asyncio.sleep(2 ** attempt) # Exponential backoff
continue
raise
except ClaudeSDKError:
raise
raise Exception("Max retries exceeded")
Logging Errors
import logging
from claude_agent_sdk import ClaudeSDKError
logger = logging.getLogger(__name__)
try:
async for message in client:
process_message(message)
except ClaudeSDKError as e:
logger.error(f"SDK error: {e}", exc_info=True)
# exc_info=True includes full stack trace
Context Managers
from contextlib import asynccontextmanager
from claude_agent_sdk import ClaudeSDKClient, ClaudeSDKError
@asynccontextmanager
async def safe_client(**options):
client = None
try:
client = ClaudeSDKClient(ClaudeAgentOptions(**options))
yield client
except ClaudeSDKError as e:
print(f"Client error: {e}")
raise
finally:
if client:
await client.close()
# Usage
async with safe_client(model="claude-sonnet-4-20250514") as client:
await client.send_message("Hello")
async for message in client:
process_message(message)