StorefrontsTroubleshooting

Troubleshooting

Common symptoms and what they actually mean.

The store shows “unavailable” / a blank store

  • FLIGHTDECK_TENANT wrong or unset (with no host mapping). In env-pinned mode the tenant must match a real store; an unknown tenant resolves to a 404. Double-check the value against your merchant console.
  • Store not live. Only a live store serves catalog/checkout. A draft or suspended store renders unavailable by design. Check the store status.
  • FLIGHTDECK_API_URL wrong. Verify it points at the real API origin and is reachable from your server.

Everything is demo data

You’re in fixture modeFLIGHTDECK_API_URL is unset, so the app serves bundled demo manifests/catalog. Set FLIGHTDECK_API_URL. In production this fallback is refused unless ALLOW_FIXTURE_MODE=1 is set, precisely so this can’t happen silently on a live domain.

Checkout returns 403

The storefront token is missing, wrong, or not reaching the server:

  • FLIGHTDECK_STOREFRONT_TOKEN isn’t set in the environment your checkout handler runs in (check Production and Preview separately in Vercel).
  • The token was rotated (an operator action today) but not updated in the deploy.
  • You’re calling checkout from the browser — the token isn’t there. Checkout must run server-side (a Route Handler / server action). See Checkout.

Every card declines

The fraud floor is doing its job. AVS/CVV defaults to enforce (fail-closed): a gateway response with no address/CVV match codes is declined. In test/dev against a fake provider, ensure the provider returns match codes. In production, this is expected for genuinely mismatched cards.

Checkout 500s after the order placed

A post-order side effect (e.g. a marketing/beacon fire) threw and wasn’t caught. The order did place; the response shouldn’t 500. Wrap any post-order side effect in try/catch and never let it fail the checkout response — retrying risks a double charge. (The starter already does this.)

Tax is $0 or checkout 422s on tax

A store configured for a real tax provider that can’t compute tax fails closed — a 422, not a silent $0-tax order. This is intentional. Fix the tax configuration in the console; don’t work around it by forcing a total.

Order history renders “no orders” but the shopper has some

You’re probably rendering the empty state on a thrown error instead of on a genuinely empty list. Distinguish 404/empty (real absence) from a thrown FlightdeckError (a failed read -> show an error state). See Accounts & orders.

store.products.get(slug) throws instead of returning null

That’s by design — an unknown slug is a real 404, surfaced as a thrown FlightdeckError with status: 404. Catch it and render your not-found page:

try {
  return await store.products.get(slug);
} catch (err) {
  if (err instanceof FlightdeckError && err.status === 404) return notFound();
  throw err;   // anything else is a real failure — don't swallow it
}

Types are stale after an API change

The SDK ships its types prebuilt — update @dscodotco/sdk to the release that matches the API surface you’re calling. Never hand-edit or patch types.generated.ts.

Rate limits and 429s

Public catalog reads are currently unthrottled — there is no per-caller rate limit on them today. Some management and operator routes do return 429 with a retry-after header when a limiter is spent. Handle 429 defensively in your client anyway (respect retry-after, back off, don’t hammer): today’s unthrottled routes are not a guarantee.

Preview deploy shows the wrong (or prod) store

Preview and production both read FLIGHTDECK_TENANT, so they serve the same store by default. To point Preview at a staging tenant, set a different FLIGHTDECK_TENANT for the Preview environment in Vercel.

Custom domain 404s

  • In host-resolved mode, the domain must be verified in your console — an unverified host is a hard 404. Verify it, or switch to env-pinned mode (FLIGHTDECK_TENANT set), which serves regardless. See Custom domains.
  • The domain may still be attached to another Vercel project. A domain can only live on one project at a time.

Still stuck?

Check your server logs — the platform logs resolution failures, declines, and tax/fraud outcomes with a reason. A failed read is logged, not swallowed, so the cause is usually right there.