Exceptions

Catch upstream provider failures, missing API keys, and configuration errors with three typed exceptions.

The PHP API throws three Kirby-typed exceptions:

ExceptionThrown byTrigger
ProviderExceptionProvidersUpstream call failed
AuthExceptionProviders, ClientMissing API key
InvalidArgumentExceptionResolverMissing or unknown provider config

ProviderException

JohannSchopplich\Copilot\AI\Exception\ProviderException extends Kirby\Exception\Exception. Thrown when an upstream AI provider call fails.

final class ProviderException extends \Kirby\Exception\Exception
{
    protected static string $defaultKey = 'copilot.ai.provider';
    protected static int $defaultHttpCode = 502;

    public function __construct(
        ProviderName $providerName,
        string $reason,
        string|null $model = null,
        string|null $responseId = null,
        string|null $responseExcerpt = null,
        int|null $httpCode = null,
        Throwable|null $previous = null,
    );
}

Details Payload

providerName
ProviderName
The provider that produced the error.
model
String | null
The model id used for the request, or null when the failure happened before model resolution.
responseId
String | null
Provider-specific response identifier (OpenAI's response.id, Anthropic's message.id).
responseExcerpt
String | null
First 200 characters of the response body, single-line, for log triage.

The original upstream error is attached as previous. The HTTP status (when available) is on the httpCode constructor argument and accessible via getHttpCode().

Message Format

The exception message is built from the constructor arguments:

<provider> provider error: <reason> (model: <model>, request: <responseId>, response: <excerpt>)

Example:

openai provider error: request failed: Rate limit reached (model: gpt-5.4-mini, request: resp_abc123, response: Rate limit exceeded for organization …)

Catching

use JohannSchopplich\Copilot\AI\Client;
use JohannSchopplich\Copilot\AI\Exception\ProviderException;

try {
    $result = Client::instance()->generateObject($messages, $schema);
} catch (ProviderException $error) {
    $details = $error->getDetails();
    // [
    //   'providerName' => ProviderName::OpenAI,
    //   'model' => 'gpt-5.4-mini',
    //   'responseId' => 'resp_abc123',
    //   'responseExcerpt' => 'Rate limit exceeded …',
    // ]

    $http = $error->getHttpCode(); // 429
    $upstream = $error->getPrevious(); // OpenAI\Exceptions\RateLimitException
}

The default HTTP code 502 surfaces when an unhandled ProviderException bubbles up through the Panel's API proxy.

AuthException

Kirby\Exception\AuthException is thrown when an API key is missing.

TriggerMessage
Provider called without apiKey setMissing API key in "johannschopplich.copilot.providers.<name>.apiKey"
Client::requireApiKey() preflight checkSame message – preflight before kicking off long-running batch ops
use JohannSchopplich\Copilot\AI\Client;
use Kirby\Exception\AuthException;

try {
    $client = Client::instance();
    $client->requireApiKey();
} catch (AuthException $error) {
    // Show a config hint to the user
}

InvalidArgumentException

Kirby\Exception\InvalidArgumentException is thrown by Resolver::fromKirbyOptions() for misconfiguration.

TriggerMessage
Missing provider configMissing required option "johannschopplich.copilot.provider"
Unknown provider nameUnknown provider "<name>" – set "johannschopplich.copilot.provider" to one of: openai, anthropic, google, mistral
For the full configuration reference, see Global Configuration.