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

# Error Handling

> HTTP status codes and error response format for the YoID APIs.

## Error Response Format

All APIs return errors in a JSON:API-style `errors` array:

```json theme={null}
{
  "errors": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "status": 400,
      "code": "VALIDATION_ERROR",
      "title": "Validation Failed",
      "detail": "The request contains invalid parameters"
    }
  ]
}
```

| Field    | Description                                                    |
| -------- | -------------------------------------------------------------- |
| `id`     | Unique error instance identifier — useful for support requests |
| `status` | HTTP status code                                               |
| `code`   | Machine-readable error code                                    |
| `title`  | Short human-readable error category                            |
| `detail` | Specific description of what went wrong                        |

<Note>
  The `errors` field is always an **array** — even for single errors. Always parse `errors[0]` rather than treating the response as a flat object.
</Note>

## HTTP Status Codes

| Status                | Code  | Description                                                                 |
| --------------------- | ----- | --------------------------------------------------------------------------- |
| OK                    | `200` | Request succeeded                                                           |
| Created               | `201` | Resource created successfully                                               |
| No Content            | `204` | Request succeeded with no response body (e.g. revocation, webhook deletion) |
| Bad Request           | `400` | Invalid or malformed parameters                                             |
| Unauthorized          | `401` | Authentication token is missing or expired                                  |
| Not Found             | `404` | The requested resource doesn't exist                                        |
| Internal Server Error | `500` | An unexpected server error — contact the YoID team                          |

## Common Errors

<AccordionGroup>
  <Accordion title="401 Unauthorized — Token Expired">
    The most common error. Your access token expires after **300 seconds** (5 minutes) with no refresh token support.

    **Fix:** Request a new token using the [token caching pattern](/api/authentication#token-caching-pattern). If you see frequent 401s, your token caching isn't refreshing proactively enough — refresh at least 30 seconds before expiry.

    ```json theme={null}
    {
      "errors": [
        {
          "id": "...",
          "status": 401,
          "code": "UNAUTHORIZED",
          "title": "Unauthorized",
          "detail": "Access token is missing or expired"
        }
      ]
    }
    ```
  </Accordion>

  <Accordion title="Existing Account — Empty Temp Password">
    Common in the YOMA ecosystem where youth interact with multiple partners. If Thandi was already onboarded by another partner, `POST /users` returns **201 Created** with an **empty `tempPassword`** — not an error code, not a different status. The only indicator is the empty string.

    **What to do:** Check `tempPassword`. If empty, the account already exists — skip onboarding emails and proceed directly to credential issuance.

    ```json theme={null}
    {
      "email": "[email protected]",
      "tempPassword": ""
    }
    ```
  </Accordion>

  <Accordion title="400 Bad Request — Validation Error">
    The request body contains invalid data.

    ```json theme={null}
    {
      "errors": [
        {
          "id": "...",
          "status": 400,
          "code": "VALIDATION_ERROR",
          "title": "Validation Failed",
          "detail": "Validation of attributes for credential template tpl_6421a8905c17830c188e2e2f failed"
        }
      ]
    }
    ```

    <Warning>
      **Attribute validation errors don't specify which attribute failed.** The `detail` message only references the template ID. To debug: compare your payload keys against the template's attribute schema. Log the template definition (via `GET /templates/credentials/{id}`) and diff it against your request.
    </Warning>
  </Accordion>

  <Accordion title="404 Not Found — Resource Missing">
    A template ID, presentation ID, or credential ID is incorrect or has been deleted.

    **Fix:** Verify the ID is correct and the resource hasn't been archived.

    ```json theme={null}
    {
      "errors": [
        {
          "id": "...",
          "status": 404,
          "code": "NOT_FOUND",
          "title": "Not Found",
          "detail": "Credential template not found"
        }
      ]
    }
    ```
  </Accordion>

  <Accordion title="500 Internal Server Error">
    An unexpected server error. Not caused by your request. Retry after a short delay.

    **Fix:** If persistent, contact the YoID team and include the error `id`.

    ```json theme={null}
    {
      "errors": [
        {
          "id": "...",
          "status": 500,
          "code": "INTERNAL_SERVER_ERROR",
          "title": "Internal Server Error",
          "detail": "An unexpected error occurred"
        }
      ]
    }
    ```
  </Accordion>
</AccordionGroup>

## Error Handling Pattern

```javascript theme={null}
async function yoidApiCall(url, options) {
  const token = await getAccessToken(); // Uses caching pattern

  const response = await fetch(url, {
    ...options,
    headers: {
      ...options.headers,
      Authorization: `Bearer ${token}`,
      "Content-Type": "application/json",
    },
  });

  if (response.status === 401) {
    // Token expired — clear cache and retry once
    clearTokenCache();
    const freshToken = await getAccessToken();
    return fetch(url, {
      ...options,
      headers: {
        ...options.headers,
        Authorization: `Bearer ${freshToken}`,
        "Content-Type": "application/json",
      },
    });
  }

  if (!response.ok) {
    const body = await response.json();
    const err = body.errors?.[0];
    throw new Error(
      `YoID API error [${err?.code}]: ${err?.detail} (id: ${err?.id})`
    );
  }

  return response;
}
```
