# Errors and request IDs

> Distinguish JSON:API, GraphQL, token, and webhook failures; use stable codes, correlation IDs, and retryability without leaking credentials.

Error shape depends on where a request failed. Keep the HTTP status,
`x-request-id`, stable error code, and surface version together. Never attach a
bearer token, client secret, trigger URL, or sensitive request body to a ticket.

## JSON:API and API plug errors

Authentication, scope, rate-limit, idempotency, and JSON:API resource errors use
an `errors` document. Plug-layer errors include a correlation ID in `meta`:

```json
{
  "errors": [
    {
      "code": "forbidden",
      "status": "403",
      "detail": "insufficient scope",
      "meta": { "correlation_id": "req_example" }
    }
  ]
}
```

The response header's `x-request-id` is the primary value to retain. Resource
validation can include source pointers or field metadata; unexpected internal
errors are intentionally generic.

## GraphQL errors

A parsed GraphQL request can return HTTP `200` with both `data` and an `errors`
array. Validation, an unknown model slug, a bad filter, query complexity, and
depth limits are field/document errors rather than JSON:API errors:

```json
{
  "errors": [
    { "message": "Operation is too complex: complexity is 300 and maximum is 200" }
  ]
}
```

Transport failures before GraphQL execution, such as an invalid token or rate
limit, use the API error envelope and their non-200 status. Check both the HTTP
status and GraphQL `errors` before using `data`.

## Token and webhook errors

Token exchange deliberately uses compact OAuth-style bodies such as
`{"error":"invalid_client"}`. Webhook ingestion uses endpoint bodies such as
`{"error":"Unauthorized"}` or `{"error":"Processing temporarily unavailable"}`.
Use the endpoint reference for the exact status and retry guidance; do not parse
human capitalization as a stable code.

## Stable codes

### unauthorized

HTTP `401`. The bearer token is missing, invalid, expired, revoked, or no longer
maps to a valid active account. Exchange once, retry once, then alert.

### missing_credentials

HTTP `401` on webhook ingestion. The service-account bearer token is missing,
invalid, or expired. Exchange once and retry once; repeated failure is a
credential problem rather than a transient delivery failure.

### forbidden

HTTP `403`. Authentication succeeded but a scope, run-as policy, or object
permission failed. Correct authorization; do not retry unchanged.

### insufficient_scope

HTTP `403` on webhook ingestion. The selected service account lacks
`webhooks`. Grant the exact scope or select the correct account.

### invalid_client

HTTP `401` from token exchange. Client credentials are absent, invalid,
inactive, revoked, or in the wrong rotation state. The response does not reveal
which component failed.

### unsupported_grant_type

HTTP `400`. Send exactly `grant_type: client_credentials`.

### not_found

HTTP `404`. The route/resource is absent or not visible to the run-as member.
Do not use it to infer cross-workspace existence.

### invalid_request

HTTP `422`. The JSON:API document failed stable resource validation. Correct the
body before retrying.

### idempotency_key_reused

HTTP `409`. The same key identified a different method/path/body fingerprint.
Reconcile the client operation; do not hide the conflict by generating a new key.

### idempotency_key_in_progress

HTTP `409`. Another request with the same key is still executing. Wait and retry
the identical request with the same key.

### rate_limited

HTTP `429`. Pause the affected credential or trigger budget for the number of
seconds in `Retry-After`.

### payload_too_large

HTTP `413` on webhook ingestion. Reduce the actual body below the configured
limit, 1 MiB by default. Changing only `Content-Length` cannot bypass the check.

### processing_failed

HTTP `422` on webhook ingestion. Stable payload or workflow validation failed.
Correct the delivery before retrying.

### unsupported_trigger_authentication

HTTP `422` on webhook ingestion. The trigger has a legacy Basic or Bearer
connector mode that conflicts with the mandatory service-account
`Authorization` header. Reconfigure the connector to API key or HMAC before
retrying.

### temporarily_unavailable

HTTP `503` on webhook ingestion. A transient processing dependency failed.
Wait for `Retry-After`, then retry with the same delivery key.

### graphql_validation

GraphQL HTTP `200` error. Correct the query, variable type, model slug, filter,
or enumerated value before retrying.

### query_too_complex

GraphQL HTTP `200` error. Reduce selected fields, page size, nesting depth, or
document size. Current defaults are complexity 200, depth 10, and 8,000 tokens.

## Support checklist

Capture the request time, method, non-secret path template, status, stable code,
`x-request-id`, `x-api-version`, retry count, and deployment release. Redact
query values or bodies that contain tenant data. Then follow
[Idempotency and retries](/platform/idempotency-retries) before repeating work.
