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

# Error Handling

> Stable error codes across both the AI API and App Builder SDK — meaning, HTTP status, and retry guidance.

HASP uses one stable set of error codes across the AI API and the App Builder SDK. The two identifiers to branch on are the **HTTP status code** and `error.code` — `error.message` is human-readable and may change without notice.

## The error envelope

Every error shares the same shape:

```json theme={null}
{
  "success": false,
  "error": {
    "code": "PHI_BLOCKED",
    "type": "forbidden",
    "message": "Message contains PHI that cannot be sent without redaction.",
    "retryable": false,
    "request_id": "req_01JQREQ000000000000000000"
  },
  "meta": {
    "request_id": "req_01JQREQ000000000000000000"
  }
}
```

Always log `request_id` — it is the key for support and for retrieving the corresponding audit record.

## Error categories

The codes fall into five categories. Each maps to an HTTP status range and a clear handling rule:

| Category                  | Typical status      | What it means                                                                                                                                                      | What to do                                                                                                        |
| ------------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------- |
| **Authentication**        | `401`               | The API key is missing, malformed, or revoked (`INVALID_API_KEY`).                                                                                                 | Fix the credential. Not retryable.                                                                                |
| **Authorization & scope** | `403`               | The key lacks a required scope (`MISSING_SCOPE`), or a feature is not enabled for the org.                                                                         | Grant the scope or enable the feature. Not retryable.                                                             |
| **Compliance / PHI**      | `402`, `403`        | No active BAA (`BAA_REQUIRED`), PHI blocked by policy (`PHI_BLOCKED`), PHI in a tool schema (`PHI_IN_TOOL_SCHEMA`), or credits exhausted (`AI_CREDITS_EXHAUSTED`). | Sign the BAA, adjust PHI mode, or top up credits. Generally not retryable until the underlying condition changes. |
| **Validation**            | `400`, `422`        | The request body failed validation (`VALIDATION_FAILED`) or an input was unprocessable. `error.param` names the offending field.                                   | Fix the request. Not retryable as-is.                                                                             |
| **Rate limit & budget**   | `429`               | RPM/daily limit hit (`RATE_LIMITED`) or a spend cap reached (`BUDGET_EXCEEDED`).                                                                                   | Honor `Retry-After` and back off. **Retryable.** See [Rate Limits](/platform/rate-limits).                        |
| **Server / upstream**     | `500`, `502`, `503` | An internal error (`INTERNAL_ERROR`), an upstream provider failure (`INFERENCE_UPSTREAM_FAILURE`), or a temporarily unavailable gateway (`INFERENCE_UNAVAILABLE`). | Retry with exponential backoff. **Retryable.**                                                                    |

## Retry guidance

The `error.retryable` boolean tells you whether a retry can ever succeed without changing the request:

* **Retry** `429` and `5xx` errors. Prefer `error.details.retry_after_seconds` (or the `Retry-After` header) when present; otherwise use exponential backoff with a ceiling.
* **Do not retry** `400`, `401`, `403`, and `422` — they require a change to the request, the credential, or the org's configuration. Retrying an identical request will fail identically.

Streaming responses deliver errors that occur after the stream opens as SSE `error` events rather than HTTP status codes — handle both paths.

## Full reference

This page is the platform-level overview. The complete code table — every code, its exact HTTP status, the `error.details` fields it carries, and a worked retry loop — lives in the AI API error reference:

<Card title="AI API Error Reference" icon="circle-exclamation" href="/ai-api/reference/errors">
  The authoritative, exhaustive list of error codes and handling patterns, including streaming errors.
</Card>
