Error Handling
Strategies for handling errors in Atlas-powered applications.
Exception Hierarchy
Atlas maps provider HTTP errors and configuration problems to typed exceptions:
AtlasException (base — extends RuntimeException, catch all Atlas errors)
├── AuthenticationException (401 — invalid API key)
├── AuthorizationException (403 — model access denied)
├── RateLimitException (429 — rate limit with retry info)
├── ProviderException (all other HTTP errors)
├── UnsupportedFeatureException (modality not supported by provider)
├── ProviderNotFoundException (provider key not registered)
├── AgentNotFoundException (agent key not found)
├── ToolNotFoundException (tool name not in registry)
└── MaxStepsExceededException (executor exceeded step limit)All exceptions live in Atlasphp\Atlas\Exceptions.
Provider Exceptions
Atlas automatically maps HTTP error codes to specific exception types:
use Atlasphp\Atlas\Exceptions\AuthenticationException;
use Atlasphp\Atlas\Exceptions\AuthorizationException;
use Atlasphp\Atlas\Exceptions\RateLimitException;
use Atlasphp\Atlas\Exceptions\ProviderException;
try {
$response = Atlas::text(Provider::OpenAI, 'gpt-4o-mini')
->message('Hello')
->asText();
} catch (AuthenticationException $e) {
// 401 — Invalid or missing API key
// $e->getMessage() includes provider name
} catch (AuthorizationException $e) {
// 403 — No access to this model
} catch (RateLimitException $e) {
// 429 — Too many requests
$retryAfter = $e->retryAfter; // Seconds to wait (from Retry-After header)
} catch (ProviderException $e) {
// All other HTTP errors (400, 500, etc.)
$e->statusCode; // HTTP status code
$e->providerMessage; // Error message from provider
$e->provider; // Provider name (e.g., 'openai')
}Catching All Atlas Errors
use Atlasphp\Atlas\Exceptions\AtlasException;
try {
$response = Atlas::agent('assistant')
->message('Hello')
->asText();
} catch (AtlasException $e) {
// Catches any Atlas exception (provider errors, config errors, etc.)
Log::error('Atlas error', ['message' => $e->getMessage()]);
}Agent & Configuration Exceptions
Agent Not Found
use Atlasphp\Atlas\Exceptions\AgentNotFoundException;
try {
$response = Atlas::agent('unknown-agent')->message('Hi')->asText();
} catch (AgentNotFoundException $e) {
// "Agent [unknown-agent] is not registered."
}Max Steps Exceeded
use Atlasphp\Atlas\Exceptions\MaxStepsExceededException;
try {
$response = Atlas::agent('assistant')->message('Hi')->asText();
} catch (MaxStepsExceededException $e) {
// Agent executor exceeded the configured step limit
// $e->limit — the max steps value
// $e->steps — the steps completed before exceeding
}Unsupported Feature
use Atlasphp\Atlas\Exceptions\UnsupportedFeatureException;
try {
$response = Atlas::image(Provider::Anthropic, 'claude-sonnet-4-5-20250929')
->prompt('Draw a cat')
->asImage();
} catch (UnsupportedFeatureException $e) {
// Provider does not support this modality
}Tool Not Found
use Atlasphp\Atlas\Exceptions\ToolNotFoundException;
try {
$response = Atlas::agent('assistant')
->tools(['nonexistent_tool'])
->message('Hi')
->asText();
} catch (ToolNotFoundException $e) {
// "Tool [nonexistent_tool] is not registered."
}Provider Not Found
use Atlasphp\Atlas\Exceptions\ProviderNotFoundException;
try {
$response = Atlas::text('invalid-provider', 'some-model')
->message('Hello')
->asText();
} catch (ProviderNotFoundException $e) {
// Provider key not registered in config
}Tool Error Handling
In tool handlers, return error strings instead of throwing exceptions. This lets the AI retry or adjust its approach:
public function handle(array $args, array $context): mixed
{
try {
$order = Order::findOrFail($args['order_id']);
return $order->toArray();
} catch (ModelNotFoundException $e) {
return 'Order not found: '.$args['order_id'];
}
}When a tool returns an error string, the AI can try a different approach. If a tool throws an exception, Atlas catches it and sends the exception message back to the model as an error result — the agent loop continues. The AgentToolCallFailed event fires with the original exception type so listeners can respond appropriately (e.g., retry on RateLimitException).
WARNING
Exception messages are sent verbatim to the model. Ensure your tool exceptions do not contain sensitive information (credentials, file paths, etc.).
Rate Limit Handling
The RateLimitException includes retry information from the provider:
use Atlasphp\Atlas\Exceptions\RateLimitException;
try {
$response = Atlas::text(Provider::OpenAI, 'gpt-4o')
->message('Hello')
->asText();
} catch (RateLimitException $e) {
$seconds = $e->retryAfter;
if ($seconds) {
// Queue a retry after the specified delay
dispatch(fn () => $this->retry($input))
->delay(now()->addSeconds($seconds));
}
}Provider Fallback
Build resilience by falling back across providers:
class ResilientService
{
public function respond(string $input): TextResponse
{
$providers = [
[Provider::OpenAI, 'gpt-4o-mini'],
[Provider::Anthropic, 'claude-sonnet-4-5-20250929'],
];
foreach ($providers as [$provider, $model]) {
try {
return Atlas::text($provider, $model)
->message($input)
->asText();
} catch (RateLimitException $e) {
Log::warning("Rate limited on {$provider->value}, trying next");
continue;
} catch (ProviderException $e) {
Log::warning("Provider error on {$provider->value}: {$e->getMessage()}");
continue;
}
}
throw new \RuntimeException('All providers failed');
}
}Laravel Exception Handler
Integrate Atlas exceptions into your application's exception handler for consistent error responses:
use Atlasphp\Atlas\Exceptions\AtlasException;
use Atlasphp\Atlas\Exceptions\RateLimitException;
use Atlasphp\Atlas\Exceptions\AuthenticationException;
// In bootstrap/app.php or your exception handler
->withExceptions(function (Exceptions $exceptions) {
$exceptions->render(function (RateLimitException $e) {
return response()->json([
'error' => 'Service temporarily unavailable. Please retry.',
'retry_after' => $e->retryAfter,
], 429);
});
$exceptions->render(function (AuthenticationException $e) {
Log::critical('AI provider authentication failed', [
'message' => $e->getMessage(),
]);
return response()->json([
'error' => 'AI service configuration error.',
], 500);
});
$exceptions->render(function (AtlasException $e) {
return response()->json([
'error' => 'An error occurred processing your request.',
], 500);
});
})Next Steps
- Testing — Test error scenarios with Atlas::fake()
- Middleware — Add error handling middleware