Troubleshooting
Common symptoms and what they actually mean.
The store shows “unavailable” / a blank store
FLIGHTDECK_TENANTwrong 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 alivestore serves catalog/checkout. Adraftorsuspendedstore renders unavailable by design. Check the store status. FLIGHTDECK_API_URLwrong. Verify it points at the real API origin and is reachable from your server.
Everything is demo data
You’re in fixture mode — FLIGHTDECK_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_TOKENisn’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_TENANTset), 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.