> ## Documentation Index
> Fetch the complete documentation index at: https://docs.craveup.com/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();
}
```

<CardGroup cols={2}>
  <Card title="Manage Cart" icon="cart-shopping" href="/guides/manage-cart">
    See the revision and idempotency lifecycle.
  </Card>

  <Card title="REST API" icon="square-terminal" href="/getting-started/rest-api">
    Review authentication boundaries and required headers.
  </Card>
</CardGroup>
