Exceptions
Catch upstream provider failures, missing API keys, and configuration errors with three typed exceptions.
The PHP API throws three Kirby-typed exceptions:
| Exception | Thrown by | Trigger |
|---|---|---|
ProviderException | Providers | Upstream call failed |
AuthException | Providers, Client | Missing API key |
InvalidArgumentException | Resolver | Missing 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.
| Trigger | Message |
|---|---|
Provider called without apiKey set | Missing API key in "johannschopplich.copilot.providers.<name>.apiKey" |
Client::requireApiKey() preflight check | Same 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.
| Trigger | Message |
|---|---|
Missing provider config | Missing required option "johannschopplich.copilot.provider" |
| Unknown provider name | Unknown provider "<name>" – set "johannschopplich.copilot.provider" to one of: openai, anthropic, google, mistral |