Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/phpaisdk/core/llms.txt

Use this file to discover all available pages before exploring further.

Every error the SDK encounters — network failures, authentication issues, rate limits, invalid requests, missing capabilities — surfaces as a typed exception that extends AiSdkException. Because all exceptions share a common base, you can catch them at a single point or handle each case specifically. The HttpErrorNormalizer maps provider HTTP responses to the correct exception class so your code stays the same regardless of which provider you use.

Base class: AiSdkException

AiSdkException extends RuntimeException and carries a $context array populated by the throwing code. All context values are accessible through typed accessor methods:
use AiSdk\Exceptions\AiSdkException;

try {
    $result = Generate::text('Hello')->model($model)->run();
} catch (AiSdkException $e) {
    $e->provider();    // ?string — provider name (e.g. 'openai')
    $e->modelId();     // ?string — model ID used in the request
    $e->status();      // ?int   — HTTP status code, if applicable
    $e->requestId();   // ?string — provider request ID from response headers
    $e->errorType();   // ?string — provider error type string
    $e->errorCode();   // ?string — provider error code string
    $e->retryAfter();  // ?int   — seconds to wait before retrying (from Retry-After header)
    $e->isRetryable(); // bool   — true for statuses 408, 409, 429, 500, 502, 503, 504, 529
    $e->body();        // mixed  — raw response body
    $e->context();     // array  — full context array
}

Exception hierarchy

AiSdkException (RuntimeException)
├── ProviderException                  — base for all provider-originated errors
│   ├── APIConnectionException         — network/connection failure (no HTTP status)
│   └── APIStatusException             — base for HTTP status errors
│       ├── AuthenticationException    — 401
│       ├── PermissionDeniedException  — 403
│       ├── NotFoundException          — 404
│       ├── InvalidRequestException    — 4xx (other 400-range)
│       ├── RateLimitException         — 429
│       ├── OverloadedException        — 529
│       └── InternalServerException    — 5xx
├── CapabilityNotSupportedException    — model lacks required capability
├── NoSuchModelException               — model not found in registry/catalog
├── MissingApiKeyException             — API key not configured
├── InvalidArgumentException           — invalid argument passed to an SDK method
├── ToolExecutionException             — tool handler threw an exception
└── InvalidToolInputException          — tool input validation failed

HTTP status mapping

HttpErrorNormalizer::normalize() maps the HTTP status code from a failed provider response to the appropriate exception class:
ExceptionHTTP StatusDescription
AuthenticationException401Invalid or missing API key
PermissionDeniedException403Access denied to the requested resource
NotFoundException404Requested resource does not exist
InvalidRequestException4xxBad request parameters (other 4xx)
RateLimitException429Rate limit exceeded
OverloadedException529Provider is overloaded
InternalServerException5xxProvider server error
ProviderExceptionotherAny other unexpected status
APIConnectionExceptionNetwork or connection failure
CapabilityNotSupportedExceptionModel does not support the required capability
NoSuchModelExceptionModel not found in the registry or catalog
MissingApiKeyExceptionAPI key environment variable not set
ToolExecutionExceptionA tool handler threw during execution
InvalidToolInputExceptionTool input failed validation

Retryable statuses

isRetryable() returns true for these HTTP statuses:
408  Request Timeout
409  Conflict
429  Too Many Requests
500  Internal Server Error
502  Bad Gateway
503  Service Unavailable
504  Gateway Timeout
529  Overloaded (Anthropic)
APIConnectionException (network failure) is not automatically marked retryable because the request may or may not have reached the provider.

Catch patterns

Catch all SDK exceptions

use AiSdk\Exceptions\AiSdkException;
use AiSdk\Generate;

try {
    $result = Generate::text('Summarise this document.')
        ->model($model)
        ->run();
} catch (AiSdkException $e) {
    logger()->error('AI request failed', [
        'provider'  => $e->provider(),
        'status'    => $e->status(),
        'requestId' => $e->requestId(),
        'message'   => $e->getMessage(),
    ]);

    throw $e;
}

Retry on retryable errors

use AiSdk\Exceptions\AiSdkException;
use AiSdk\Generate;

function generateWithRetry(int $maxAttempts = 3): string
{
    $attempt = 0;

    while (true) {
        try {
            return Generate::text('Hello')->model($model)->run()->text;
        } catch (AiSdkException $e) {
            $attempt++;

            if (! $e->isRetryable() || $attempt >= $maxAttempts) {
                throw $e;
            }

            $wait = $e->retryAfter() ?? (2 ** $attempt); // exponential back-off
            sleep($wait);
        }
    }
}

Catch specific exceptions

use AiSdk\Exceptions\RateLimitException;

try {
    $result = Generate::text('Hello')->model($model)->run();
} catch (RateLimitException $e) {
    $retryAfter = $e->retryAfter() ?? 60;
    // Queue the job to retry after $retryAfter seconds.
    dispatch(new RetryJob())->delay(now()->addSeconds($retryAfter));
}

HttpErrorNormalizer

Provider adapters call HttpErrorNormalizer::normalize() when they receive a non-2xx response. You don’t need to call this directly, but understanding it helps when writing custom provider adapters.
use AiSdk\Utils\Errors\HttpErrorNormalizer;

$exception = HttpErrorNormalizer::normalize(
    provider:    'openai',
    status:      429,
    body:        ['error' => ['message' => 'Rate limit exceeded.']],
    requestId:   'req_abc123',
    modelId:     'gpt-4o',
    retryAfter:  30,
);

// $exception is a RateLimitException with isRetryable() === true
The normalizer extracts the human-readable message from the response body by checking error.message, error, or message keys, then falls back to a generic "{provider} request failed with status {status}." string.
ClassExtendsNamespace
AiSdkExceptionRuntimeExceptionAiSdk\Exceptions
ProviderExceptionAiSdkExceptionAiSdk\Exceptions
APIStatusExceptionProviderExceptionAiSdk\Exceptions
APIConnectionExceptionProviderExceptionAiSdk\Exceptions
AuthenticationExceptionAPIStatusExceptionAiSdk\Exceptions
PermissionDeniedExceptionAPIStatusExceptionAiSdk\Exceptions
NotFoundExceptionAPIStatusExceptionAiSdk\Exceptions
InvalidRequestExceptionAPIStatusExceptionAiSdk\Exceptions
RateLimitExceptionAPIStatusExceptionAiSdk\Exceptions
OverloadedExceptionAPIStatusExceptionAiSdk\Exceptions
InternalServerExceptionAPIStatusExceptionAiSdk\Exceptions
CapabilityNotSupportedExceptionAiSdkExceptionAiSdk\Exceptions
NoSuchModelExceptionAiSdkExceptionAiSdk\Exceptions
MissingApiKeyExceptionAiSdkExceptionAiSdk\Exceptions
InvalidArgumentExceptionAiSdkExceptionAiSdk\Exceptions
ToolExecutionExceptionAiSdkExceptionAiSdk\Exceptions
InvalidToolInputExceptionAiSdkExceptionAiSdk\Exceptions

Build docs developers (and LLMs) love