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

# Error Codes

> Handle public Storefront API errors without leaking credentials or replaying unsafe writes.

Every Storefront API error has a stable machine-readable code and a request ID:

```json theme={null}
{
  "code": "CART_CONFLICT",
  "message": "The cart changed. Refresh it and try again.",
  "requestId": "req_123",
  "details": {}
}
```

## SDK errors

```ts theme={null}
import {
  StorefrontApiError,
  StorefrontClientStateError,
  StorefrontProtocolError,
  StorefrontTimeoutError,
} from "@craveup/storefront-sdk";

try {
  await storefront.cart.addItem(locationId, cartId, payload);
} catch (error) {
  if (error instanceof StorefrontApiError) {
    console.error(error.code, error.requestId);
    if (error.retryAfterMs !== undefined) scheduleRetry(error.retryAfterMs);
  } else if (error instanceof StorefrontClientStateError) {
    console.error(error.code);
  } else if (error instanceof StorefrontProtocolError) {
    console.error(error.reason, error.method, error.routeTemplate);
  } else if (error instanceof StorefrontTimeoutError) {
    showRetryMessage();
  }
}
```

`StorefrontApiError.retryAfterMs` is a bounded millisecond delay parsed from a
valid `Retry-After` response header, or `undefined` when no usable delay was
provided. `StorefrontClientStateError` is a local preflight failure; for
example, `CUSTOMER_AUTH_REQUIRED` means no customer JWT was available and no
request was sent. `StorefrontProtocolError.reason` is `EMPTY_RESPONSE` or
`INVALID_JSON` when a successful response violates the SDK's JSON contract.
Neither error retains response content, credentials, or secrets.

Do not log capability, JWT, receipt-token, authorization, or payment-secret values with an error.

## Public error codes

| Code | Typical status | Client behavior |
| - | - | - |
| `VALIDATION_ERROR` | 400 or 422 | Correct the fields described in `details` |
| `UNAUTHORIZED` | 401 | Restore the matching cart capability or reauthenticate the customer |
| `FORBIDDEN` | 403 | Stop; the authenticated principal does not own the resource |
| `NOT_FOUND` | 404 | Treat the resource as unavailable; protected endpoints may conceal existence |
| `RATE_LIMITED` | 429 | Honor `Retry-After` and back off |
| `CART_CONFLICT` | 409 | Fetch the latest cart and require an explicit retry |
| `RESOURCE_CONFLICT` | 409 | Refresh the affected customer resource before retrying |
| `CART_IMMUTABLE` | 409 | Stop mutating a locked, completed, or expired cart |
| `IDEMPOTENCY_KEY_REQUIRED` | 400 | Retry once with a stable unique key for that logical write |
| `IDEMPOTENCY_KEY_REUSED` | 409 | Generate a new key because the old key belongs to different input |
| `IDEMPOTENCY_IN_PROGRESS` | 409 | Poll or retry with bounded backoff using the same logical operation |
| `DEPENDENCY_UNAVAILABLE` | 503 | Show a temporary failure and retry with backoff |
| `INTERNAL_ERROR` | 500 | Show a generic message and retain the request ID for support |

## Retry rules

Retry reads and explicitly retryable failures such as `RATE_LIMITED` or
`DEPENDENCY_UNAVAILABLE` with exponential backoff. Prefer `retryAfterMs` when
the API supplies it. Treat `StorefrontProtocolError` as an upstream contract or
edge-transformation failure, retain its method and route template for support,
and retry only when the underlying operation is safe. Never automatically
replay a cart mutation after `CART_CONFLICT`, and never invent a new idempotency
key while the outcome of an earlier write is unknown.

```ts theme={null}
if (error instanceof StorefrontApiError && error.code === "CART_CONFLICT") {
  const cart = await storefront.cart.get(locationId, cartId);
  replaceCartState(cart);
  askCustomerToRetry();
}
```

> [card] [Manage Cart](/docs/guides/manage-cart.md)
>
> See the revision and idempotency lifecycle.

> [card] [REST API](/docs/getting-started/rest-api.md)
>
> Review authentication boundaries and required headers.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.