Error Handling#

GraphQL errors are returned in the errors array of the response.

Tip:The HTTP status code is always 200 for GraphQL responses — even when errors occur. Always check the errors field in the response body to detect failures, not the HTTP status.

Error response shape#

Each error object in the errors array has the following fields:

NameTypeRequiredDescription
message
String!
RequiredHuman-readable error message
path
[String!]
OptionalPath to the field that caused the error (e.g. ["inventory"])
extensions
Object
OptionalAdditional error metadata
{
  "data": null,
  "errors": [
    {
      "message": "Unauthorized",
      "extensions": {
        "code": "UNAUTHORIZED"
      }
    }
  ]
}

Error codes#

NameTypeRequiredDescription
UNAUTHORIZED
HTTP 401
OptionalMissing or invalid API key. **Fix:** Ensure your `Authorization: Bearer <key>` header is present and the key has not expired or been revoked.
FORBIDDEN
HTTP 403
OptionalValid key but insufficient permissions. **Fix:** Check key scopes in **Settings → API** — your key may not have access to this resource or operation.
NOT_FOUND
HTTP 404
OptionalThe requested resource does not exist. **Fix:** Verify the ID or slug in your query arguments; the resource may have been deleted or never existed.
VALIDATION_ERROR
HTTP 422
OptionalInput failed server-side validation. **Fix:** Check `extensions.field` to identify which input field failed, then verify required fields and correct formats.
RATE_LIMITED
HTTP 429
OptionalToo many requests in a short period. **Fix:** Apply exponential back-off before retrying. Cache frequently-accessed data to reduce request volume. See [Rate Limits](/docs/graphql/rate-limits).
INTERNAL_SERVER_ERROR
HTTP 500
OptionalUnexpected server error. **Fix:** Retry with exponential back-off. If the error persists, contact support with the full error response and your request details.
·
Note:The HTTP status codes above are semantic equivalents only — the actual HTTP response will always be 200. Use extensions.code to handle errors programmatically.

Validation errors#

When VALIDATION_ERROR is returned, the extensions object includes a field key identifying which input field failed:

{
  "errors": [
    {
      "message": "postal_code is required",
      "extensions": {
        "code": "VALIDATION_ERROR",
        "field": "postal_code"
      }
    }
  ]
}

Partial responses#

A response can contain both data and errors — some fields succeeded, others failed. Always check errors even when data is present.

{
  "data": {
    "product": { "sku": "BLK-HOODIE-M", "label": "Black Hoodie M" },
    "inventory": null
  },
  "errors": [
    {
      "message": "Could not fetch inventory",
      "path": ["inventory"],
      "extensions": { "code": "INTERNAL_SERVER_ERROR" }
    }
  ]
}

Handling errors in code#

const result = await fetch('https://afosto.app/graphql', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ query, variables }),
})

const { data, errors } = await result.json()

if (errors?.length) {
  for (const error of errors) {
    const code = error.extensions?.code
    switch (code) {
      case 'UNAUTHORIZED':
        // Redirect to login or refresh token
        break
      case 'RATE_LIMITED':
        // Retry after delay
        break
      case 'VALIDATION_ERROR':
        // Show field-level error to user
        console.error('Field error:', error.extensions?.field, error.message)
        break
      default:
        console.error('GraphQL error:', code, error.message)
    }
  }
}
Query Runnerhttps://afosto.app/graphql

No query loaded

Click play on any code block in the docs to load a query here.