Troubleshooting catalog
Search this page (Ctrl+F) for the exact error message you're seeing. Each entry: symptom → cause → fix.
Auth + handoff
"Not authenticated" / 401 from satellites after SlabTrack login
Cause: JWT_SECRET doesn't match across SlabTrack + ToT + Storefront. Each repo verifies the JWT against its own env var; if they differ, valid tokens get rejected.
Fix: Set the same JWT_SECRET on all three Railway services. Trigger redeploys.
"You don't have access to this shop" on Storefront dashboard
Cause: Storefront's Storefront.ownerUserId doesn't match your SlabTrack user id, OR the JWT is being issued for a different user.
Fix: Verify in the Storefront DB that ownerUserId on the row matches your SlabTrack users.id. If you migrated databases, the IDs may have shifted.
Stripe
Webhook returns 401 Signature mismatch
Cause: STRIPE_WEBHOOK_SECRET doesn't match the signing secret of the webhook endpoint that's hitting you. Test mode and live mode have different secrets.
Fix: In Stripe dashboard → Developers → Webhooks → click your endpoint → reveal signing secret → paste into Railway. Redeploy.
Order stays "pending" forever after a paid purchase
Cause: Webhook never fired or never completed. Check the Stripe dashboard's webhook log — was the event delivered?
Fix: If undelivered, check your endpoint URL is reachable + signing secret is correct. If delivered but still pending, check Railway logs around the timestamp for an exception during webhook processing.
"Cards already committed to another channel" 409 on Strategist commit
Cause: The duplicate guard in the commit endpoint detected at least one card already has an active card_channels row for a non-personal channel.
Fix: If those cards genuinely should be re-committed, run Sync Center → "Reconcile Now" first to clear stale rows. The 409 response includes a conflicts[] array with the offending card IDs.
Refund fails with "Charge has already been refunded"
Cause: Stripe's idempotency key is correctly preventing double-refund.
Fix: Not a bug — the original refund already went through. Check Stripe dashboard for the existing refund.
Shipping
"Ship-from address not configured" on ToT label print
Cause: One or more of the six SHIP_FROM_* env vars unset on ToT.
Fix: Set all of: SHIP_FROM_NAME, SHIP_FROM_STREET, SHIP_FROM_CITY, SHIP_FROM_STATE, SHIP_FROM_ZIP, SHIP_FROM_PHONE. The error message lists which are missing.
"SHIPPO_API_TOKEN not set"
Cause: Token env var unset OR using the legacy name SHIPPO_API_KEY alone.
Fix: Set SHIPPO_API_TOKEN (the canonical name). Code falls back to SHIPPO_API_KEY if only that's set, but new deploys should use SHIPPO_API_TOKEN for consistency with Storefront.
Label prints but USPS rejects with "TEST" stamp
Cause: You're using a test Shippo token. Test labels look real but aren't accepted by USPS.
Fix: Switch to live token. Update Shippo billing first or label purchase will 402 charge required.
Sync + drift
Card shows as "on ToT" in Command Bridge but isn't actually listed there
Cause: Drift — operator manually delisted on ToT without going through SlabTrack's bridge, so card_channels still has the active row.
Fix: Sync Center → "Reconcile Now". The reconciler asks ToT for its canonical active list and clears stale SlabTrack rows.
Card sold on ToT but still listed on Storefront afterward
Cause: Bulk-disengage webhook didn't fire OR Storefront didn't process it.
Fix: Sync Center → "Reconcile Now" to clear. Check Storefront webhook logs for failed bulk-disengage delivery.
Strategist commit succeeds but cards never appear on ToT browse
Cause: Webhook delivered but auto-publish failed silently. Could be: schema migration didn't run on ToT (Listing table missing fields), Prisma generate didn't update.
Fix: Check ToT Railway logs around the commit timestamp. Look for "[webhook/ingest] auto-listing failed" entries — the response also includes a listing_errors[] array.
Theme Studio
Save succeeds but public storefront unchanged
Cause: Browser cache OR you clicked a preset that doesn't include the field you expected. Cinematic preset doesn't set logoUrl; only "Apply SlabTrack Showcase" does.
Fix: Hard refresh (Ctrl+Shift+R / Cmd+Shift+R). Check the API response: GET /api/storefronts/[slug] — verify the field actually persisted.
Logo URL set but shows "S" placeholder
Cause: URL doesn't actually serve an image. The fallback in ShopLogo hides broken-image icons by reverting to letter-avatar.
Fix: Open the URL directly in a new tab. If it returns HTML or 404, host the image somewhere reliable. The default https://storefront.slabtrack.io/slabtrack-logo.png always works for the SlabTrack showcase.
Database / migrations
"column does not exist" errors after schema change
Cause: Prisma db push didn't run, OR ran but failed silently (Railway's start script uses || true).
Fix: Check Railway's start logs for prisma db push output. If errors, fix the schema + redeploy. Manual remedy: railway run npx prisma db push --accept-data-loss from your local terminal.