> ## Documentation Index
> Fetch the complete documentation index at: https://phaseo.app/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors and Debugging

> Understand Phaseo error responses and fix common request, provider, and routing issues faster.

Use this page to understand what A Phaseo error means and what to do next.

Every error response follows the same JSON format, so your app can handle failures consistently across models and providers.

## Example error response

```json theme={null}
{
  "generation_id": "G-abc123",
  "status_code": 502,
  "error": "upstream_error",
  "error_type": "system",
  "error_origin": "upstream",
  "reason": "all_candidates_failed",
  "description": "Provider \"google-ai-studio\" failed with HTTP 403 for endpoint \"responses\" on model \"google/gemini-2.5-pro\".",
  "attempt_count": 1,
  "failed_providers": ["google-ai-studio"],
  "failed_statuses": [403],
  "provider_failure_diagnostics": {
    "category": "provider_access_missing",
    "hint": "The provider account appears not to have access to this model or feature yet. Verify account entitlements and provider-side access.",
    "provider": "google-ai-studio"
  },
  "upstream_error": {
    "code": "PERMISSION_DENIED",
    "message": "The caller does not have permission.",
    "description": null,
    "param": null
  },
  "failure_sample": [
    {
      "provider": "google-ai-studio",
      "type": "upstream_non_2xx",
      "status": 403,
      "upstream_error_code": "PERMISSION_DENIED",
      "upstream_error_message": "The caller does not have permission.",
      "upstream_error_description": null,
      "upstream_error_param": null,
      "upstream_payload_preview": "{\"error\":{\"status\":\"PERMISSION_DENIED\"}}",
      "retryable": false
    }
  ]
}
```

## Fields you will always get

* `generation_id`: a stable request ID you can share with support.
* `status_code`: mirrors the HTTP status code.
* `error`: a machine-readable error code, such as `validation_error`.
* `error_type`: a high-level class, usually `user` or `system`.
* `error_origin`: whether the problem was mainly caused by the caller, Phaseo, or an upstream provider.
* `description`: a plain-language explanation of what happened.
* `details` (optional): structured validation details when the error is a request-validation problem.

## Extra fields you may see

Some errors include more detail to help you fix the issue faster:

* `reason`: a more specific subreason such as `all_candidates_failed` or `pricing_not_configured`.
* `provider_candidate_diagnostics` and `provider_enablement`: explain why a model could not be used with the requested endpoint.
* `routing_diagnostics`: extra detail about how routing or availability checks narrowed the request.
* `provider_failure_diagnostics`: hints for missing credentials, missing access, region restrictions, rate limits, and similar provider-side failures.
* `upstream_error` and `failure_sample`: best-effort summaries of the first provider failure when the request reached a provider.
* `failed_providers`, `failed_statuses`, and `attempt_count`: extra retry and failover context.

## Status class guidance

| Status    | Meaning                              | Recommended action                                  |
| --------- | ------------------------------------ | --------------------------------------------------- |
| `400-499` | Request, auth, or permission problem | Fix the request or credentials before retrying.     |
| `429`     | Provider or route-level throttling   | Retry with backoff and respect `Retry-After`.       |
| `500-599` | Phaseo or upstream provider failure  | Retry with jittered backoff and log the request ID. |

## Common error codes

| Type                   | HTTP Status | Description                                              |
| ---------------------- | ----------- | -------------------------------------------------------- |
| `authentication_error` | `401`       | Missing or invalid API key.                              |
| `authorization_error`  | `403`       | The key does not have access to this resource.           |
| `not_found_error`      | `404`       | The endpoint or resource could not be found.             |
| `rate_limit_error`     | `429`       | Too many requests. Retry after the specified delay.      |
| `validation_error`     | `400`       | Invalid parameters or request body.                      |
| `provider_error`       | `502`       | The upstream model provider failed to respond correctly. |
| `server_error`         | `500`       | An unexpected issue happened inside Phaseo.              |

## When a provider fails

If Phaseo reached a provider but the request still failed, you may see:

* `provider_failure_diagnostics.category`
* `provider_failure_diagnostics.hint`
* `provider_failure_diagnostics.provider`

Current categories include:

* `credentials_not_configured`
* `credentials_invalid_or_forbidden`
* `provider_access_missing`
* `region_or_project_restriction`
* `model_unavailable_for_endpoint`
* `rate_limited`
* `server_error`

These fields are meant to help you fix the problem without turning on full debug mode.

## When a model or endpoint is not available

For `unsupported_model_or_endpoint` responses, Phaseo may include:

* `provider_candidate_diagnostics`
* `provider_enablement`
* `missing_pricing_providers`
* `routing_diagnostics`

This helps you distinguish between:

* a known model that is not active yet
* a model that does not support the endpoint you asked for
* missing pricing data
* rollout or internal availability restrictions

Common fields:

* `provider_candidate_diagnostics.totalProviders`: how many providers were known for the model before endpoint filtering.
* `provider_candidate_diagnostics.supportsEndpointCount`: how many of those providers support the requested endpoint.
* `provider_candidate_diagnostics.candidateCount`: how many providers remained after adapter checks.
* `provider_candidate_diagnostics.droppedUnsupportedEndpoint`: providers dropped because they do not support the endpoint.
* `provider_candidate_diagnostics.droppedMissingAdapter`: provider/endpoint pairs dropped because there is no gateway adapter for that endpoint yet.
* `provider_enablement.capability`: the capability gate being enforced, such as `video_generation`.
* `provider_enablement.providersBefore` / `provider_enablement.providersAfter`: providers before and after capability or enablement filtering.
* `provider_enablement.dropped[].reason`: machine-readable reasons such as `pricing_missing`.
* `routing_diagnostics.filterStages[].stage`: the routing stage, for example capability, rollout, or routing-status filtering.
* `routing_diagnostics.filterStages[].beforeCount` / `routing_diagnostics.filterStages[].afterCount`: provider counts before and after each stage.
* `routing_diagnostics.filterStages[].droppedProviders[].reason`: machine-readable reasons such as rollout or routing restrictions.

### Example

```json theme={null}
{
  "generation_id": "G-unsupported123",
  "status_code": 400,
  "error": "unsupported_model_or_endpoint",
  "description": "No provider is currently routable for endpoint \"responses\" on model \"example/model\".",
  "provider_candidate_diagnostics": {
    "totalProviders": 3,
    "supportsEndpointCount": 2,
    "candidateCount": 1,
    "droppedUnsupportedEndpoint": ["provider-a"],
    "droppedMissingAdapter": [
      {
        "providerId": "provider-b",
        "endpoint": "responses"
      }
    ]
  },
  "provider_enablement": {
    "capability": "responses",
    "providersBefore": ["provider-b", "provider-c"],
    "providersAfter": ["provider-c"],
    "dropped": [
      {
        "providerId": "provider-b",
        "reason": "pricing_missing"
      }
    ]
  },
  "routing_diagnostics": {
    "filterStages": [
      {
        "stage": "provider_routing_status",
        "beforeCount": 1,
        "afterCount": 0,
        "droppedProviders": [
          {
            "providerId": "provider-c",
            "reason": "provider_status_not_ready"
          }
        ]
      }
    ]
  }
}
```

## Optional debug mode

Most request schemas support a `debug` object for controlled troubleshooting:

```json theme={null}
{
  "debug": {
    "enabled": true,
    "return_upstream_request": true,
    "return_upstream_response": false,
    "trace": true,
    "trace_level": "summary"
  }
}
```

Available fields:

* `enabled`
* `return_upstream_request`
* `return_upstream_response`
* `trace`
* `trace_level` (`summary` or `full`)

Use debug mode in development or tightly controlled environments only.

## Retry strategy

* **400-series errors:** Fix your request before retrying.
* **429:** Implement exponential backoff and honor the `Retry-After` header.
* **500-series errors:** Retry safely after a short delay.

Example:

```js theme={null}
if (error.error === "rate_limit_error") {
  await sleep(retryAfterMs);
  return retryRequest();
}
```

## Streaming-specific notes

* If the request fails before streaming begins, you get a standard JSON error payload.
* If it fails mid-stream, treat the partial stream as incomplete and show a retry option.
* Always capture `generation_id` and endpoint/model metadata in logs.

## Troubleshooting tips

* Check the [Gateway status page](https://phaseo.app/status) for ongoing incidents.
* Review your request payload against the endpoint docs.
* Share `generation_id` when contacting support.

## Related resources

<Columns cols={2}>
  <Card title="Authentication" icon="key" href="./authentication">
    Authenticate with bearer API keys.
  </Card>

  <Card title="Limits" icon="gauge" href="./limits.mdx">
    Handle provider-driven throttling and retries.
  </Card>

  <Card title="Streaming" icon="radio" href="./streaming.mdx">
    Use SSE safely in production flows.
  </Card>
</Columns>

If you are implementing error handling as an agent:

* Use repository skills for retry logic, structured logging, and schema-safe error parsing.
* Treat debug payloads as potentially sensitive and redact before persistent logs.
* Prefer deterministic retries (bounded attempts + jitter) over unbounded loops.
