Skip to main content
Prism Vertex provides comprehensive error handling for all API requests. When a request fails, the package throws specific exception types that help you identify and handle different error conditions.

Exception hierarchy

All Vertex AI errors extend from Prism’s base exception classes:
Illuminate\Http\Client\RequestException
    └── Prism\Prism\Exceptions\PrismException
        ├── Prism\Prism\Exceptions\PrismRequestTooLargeException
        ├── Prism\Prism\Exceptions\PrismRateLimitedException
        └── Prism\Prism\Exceptions\PrismProviderOverloadedException

HTTP status code mapping

Prism Vertex maps HTTP status codes to specific exception types:
Status CodeExceptionDescription
413PrismRequestTooLargeExceptionRequest payload exceeds size limit
429PrismRateLimitedExceptionRate limit exceeded
503PrismProviderOverloadedExceptionProvider is temporarily overloaded
529PrismProviderOverloadedExceptionProvider is temporarily overloaded
OtherPrismExceptionGeneral error with details

Implementation

The status code mapping is handled by Vertex::handleRequestException():
public function handleRequestException(string $model, RequestException $e): never
{
    match ($e->response->getStatusCode()) {
        413 => throw PrismRequestTooLargeException::make(class_basename($this)),
        429 => throw PrismRateLimitedException::make([]),
        503, 529 => throw PrismProviderOverloadedException::make(class_basename($this)),
        default => $this->handleResponseErrors($e),
    };
}

Error response formats

Vertex AI returns errors in multiple formats depending on the provider and schema. Prism Vertex normalizes these into a consistent exception format.

Standard Google API errors

Most Google Vertex AI errors follow the google.rpc.Status format:
{
  "error": {
    "code": 400,
    "message": "Invalid argument",
    "status": "INVALID_ARGUMENT"
  }
}

Anthropic partner errors

Anthropic models via :rawPredict return errors in Anthropic’s format:
{
  "type": "error",
  "error": {
    "type": "invalid_request_error",
    "message": "messages: field required"
  }
}

OpenAI-compatible errors

OpenAI-schema models return errors similar to the OpenAI API:
{
  "error": {
    "type": "invalid_request_error",
    "message": "Invalid model specified"
  }
}

Array-wrapped errors

Some endpoints wrap errors in an array:
[
  {
    "error": {
      "code": 400,
      "message": "Bad request"
    }
  }
]

Field violation details

Google API errors may include detailed field violations:
{
  "error": {
    "code": 400,
    "message": "Invalid request",
    "status": "INVALID_ARGUMENT",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.BadRequest",
        "fieldViolations": [
          {
            "field": "messages[0].content",
            "description": "content must not be empty"
          }
        ]
      }
    ]
  }
}

Error extraction

Prism Vertex uses Vertex::extractError() to normalize all error formats:
public static function extractError(?array $data, ?string $rawBody = null): array
{
    if ($data === null || $data === []) {
        return [null, $rawBody ?: null];
    }

    // Array-wrapped response: [{"error": {...}}]
    if (array_is_list($data) && isset($data[0])) {
        $data = $data[0];
    }

    // Anthropic partner model errors: {"type": "error", "error": {...}}
    if (data_get($data, 'type') === 'error') {
        return [
            data_get($data, 'error.type'),
            data_get($data, 'error.message'),
        ];
    }

    $error = data_get($data, 'error');

    if ($error === null) {
        return [null, $rawBody ?: null];
    }

    // Flat string error: {"error": "some string"}
    if (is_string($error)) {
        return [null, $error];
    }

    // Standard google.rpc.Status or OpenAI-compatible
    $errorType = data_get($error, 'status') ?? data_get($error, 'type');
    $errorMessage = data_get($error, 'message');

    // Append field violation details
    $details = data_get($error, 'details', []);
    if (is_array($details)) {
        foreach ($details as $detail) {
            if (data_get($detail, '@type') === 'type.googleapis.com/google.rpc.BadRequest') {
                $violations = data_get($detail, 'fieldViolations', []);
                if (is_array($violations) && $violations !== []) {
                    $parts = [];
                    foreach ($violations as $v) {
                        $field = data_get($v, 'field', '');
                        $desc = data_get($v, 'description', '');
                        $parts[] = $field !== '' ? "{$field}: {$desc}" : $desc;
                    }
                    $errorMessage = ($errorMessage ?? '').'. Field violations: '.implode('; ', $parts);
                }
            }
        }
    }

    return [$errorType, $errorMessage];
}
The extracted error type and message are used to create a detailed PrismException.

Catching exceptions

Basic error handling

use Prism\Prism\Prism;
use Prism\Prism\Exceptions\PrismException;
use Prism\Vertex\Enums\Vertex;

try {
    $response = Prism::text()
        ->using(Vertex::Gemini, 'gemini-2.5-flash')
        ->withPrompt('Explain quantum computing')
        ->asText();

    echo $response->text;
} catch (PrismException $e) {
    // Handle any Prism error
    logger()->error('Vertex AI request failed', [
        'message' => $e->getMessage(),
        'code' => $e->getCode(),
    ]);
}

Handling specific error types

use Prism\Prism\Prism;
use Prism\Prism\Exceptions\PrismException;
use Prism\Prism\Exceptions\PrismRateLimitedException;
use Prism\Prism\Exceptions\PrismRequestTooLargeException;
use Prism\Prism\Exceptions\PrismProviderOverloadedException;
use Prism\Vertex\Enums\Vertex;

try {
    $response = Prism::text()
        ->using(Vertex::Gemini, 'gemini-2.5-flash')
        ->withPrompt('Explain quantum computing')
        ->asText();
} catch (PrismRateLimitedException $e) {
    // Wait and retry
    sleep(5);
    // Retry logic here
} catch (PrismRequestTooLargeException $e) {
    // Request is too large, reduce input size
    logger()->warning('Request too large, try reducing prompt length');
} catch (PrismProviderOverloadedException $e) {
    // Provider is overloaded, use exponential backoff
    logger()->warning('Provider overloaded, retrying later');
} catch (PrismException $e) {
    // Other errors
    logger()->error('Request failed: ' . $e->getMessage());
}

Retry strategies

You can configure automatic retries using Prism’s built-in retry mechanism:
use Prism\Prism\Prism;
use Prism\Vertex\Enums\Vertex;

$response = Prism::text()
    ->using(Vertex::Gemini, 'gemini-2.5-flash')
    ->withClientRetry(
        maxAttempts: 3,
        delayMs: 1000,
        multiplier: 2.0,
        retryOnTimeout: true
    )
    ->withPrompt('Explain quantum computing')
    ->asText();
This will retry the request up to 3 times with exponential backoff (1s, 2s, 4s).

Manual retry with exponential backoff

use Prism\Prism\Prism;
use Prism\Prism\Exceptions\PrismRateLimitedException;
use Prism\Prism\Exceptions\PrismProviderOverloadedException;
use Prism\Vertex\Enums\Vertex;

$maxRetries = 3;
$baseDelay = 1; // seconds

for ($attempt = 0; $attempt < $maxRetries; $attempt++) {
    try {
        $response = Prism::text()
            ->using(Vertex::Gemini, 'gemini-2.5-flash')
            ->withPrompt('Explain quantum computing')
            ->asText();

        break; // Success, exit loop
    } catch (PrismRateLimitedException | PrismProviderOverloadedException $e) {
        if ($attempt === $maxRetries - 1) {
            throw $e; // Last attempt failed
        }

        $delay = $baseDelay * (2 ** $attempt);
        logger()->warning("Attempt {$attempt} failed, retrying in {$delay}s");
        sleep($delay);
    }
}

Common error scenarios

Invalid model name

try {
    Prism::text()
        ->using(Vertex::Gemini, 'invalid-model-name')
        ->withPrompt('Hello')
        ->asText();
} catch (PrismException $e) {
    // Error type: NOT_FOUND or INVALID_ARGUMENT
    // Message: "Model not found" or similar
}

Missing configuration

// If project_id and location are missing in Standard mode:
try {
    Prism::text()
        ->using(Vertex::Anthropic, 'claude-3-5-sonnet@20241022')
        ->withPrompt('Hello')
        ->asText();
} catch (PrismException $e) {
    // Message: "Vertex AI Standard mode requires both project_id
    // and location to be configured..."
}

Invalid credentials file

// If credentials file doesn't exist:
try {
    Prism::text()
        ->using(Vertex::Gemini, 'gemini-2.5-flash')
        ->withPrompt('Hello')
        ->asText();
} catch (PrismException $e) {
    // Message: "Vertex AI credentials file not found: /path/to/file.json"
}

Express mode with partner models

// If using Express mode (no project_id/location) with non-Gemini schema:
try {
    Prism::text()
        ->using(Vertex::Anthropic, 'claude-3-5-sonnet@20241022')
        ->withPrompt('Hello')
        ->asText();
} catch (PrismException $e) {
    // Message: "Vertex AI Express mode only supports Google models.
    // The anthropic apiSchema requires Standard mode with project_id and location."
}

Invalid JSON schema

use Prism\Prism\Prism;
use Prism\Prism\Schema\ObjectSchema;
use Prism\Prism\Schema\StringSchema;
use Prism\Vertex\Enums\Vertex;

$schema = new ObjectSchema(
    name: 'answer',
    properties: [
        new StringSchema('', 'Empty name'),  // Invalid: empty name
    ]
);

try {
    Prism::structured()
        ->using(Vertex::Gemini, 'gemini-2.5-flash')
        ->withSchema($schema)
        ->withPrompt('Hello')
        ->asStructured();
} catch (PrismException $e) {
    // Error type: INVALID_ARGUMENT
    // Message: Field violations: schema.properties[0].name: must not be empty
}

Debugging failed requests

The PrismException includes the original HTTP response for debugging:
use Prism\Prism\Prism;
use Prism\Prism\Exceptions\PrismException;
use Prism\Vertex\Enums\Vertex;

try {
    $response = Prism::text()
        ->using(Vertex::Gemini, 'gemini-2.5-flash')
        ->withPrompt('Explain quantum computing')
        ->asText();
} catch (PrismException $e) {
    // Log full error details
    logger()->error('Vertex AI error', [
        'message' => $e->getMessage(),
        'code' => $e->getCode(),
        'previous' => $e->getPrevious(),
    ]);

    // Access the original HTTP response if available
    if ($previous = $e->getPrevious()) {
        if ($previous instanceof \Illuminate\Http\Client\RequestException) {
            $statusCode = $previous->response->getStatusCode();
            $body = $previous->response->body();
            $json = $previous->response->json();

            logger()->debug('HTTP response', [
                'status' => $statusCode,
                'body' => $body,
                'json' => $json,
            ]);
        }
    }
}
All PrismException instances thrown by Vertex include detailed error information extracted from the API response, making it easier to diagnose and fix issues.

Testing error handling

You can test error handling using Laravel’s HTTP fake:
use Illuminate\Support\Facades\Http;
use Prism\Prism\Prism;
use Prism\Prism\Exceptions\PrismRateLimitedException;
use Prism\Vertex\Enums\Vertex;

Http::fake([
    '*' => Http::response([
        'error' => [
            'code' => 429,
            'message' => 'Rate limit exceeded',
            'status' => 'RESOURCE_EXHAUSTED',
        ],
    ], 429),
]);

try {
    Prism::text()
        ->using(Vertex::Gemini, 'gemini-2.5-flash')
        ->withPrompt('Hello')
        ->asText();
} catch (PrismRateLimitedException $e) {
    // Expected
    $this->assertStringContainsString('Rate limit', $e->getMessage());
}

Build docs developers (and LLMs) love