Ship/Now

Guides · 3 min

Troubleshooting

The failures that look like something else, and the one line that fixes each.

The Supabase email templates are still the defaults, which return the session in a URL fragment your server never sees. Rewrite all three to use ?token_hash={{ .TokenHash }}. See Authentication.

I sign in, then I am signed out on the next page

proxy.ts is not running, or it is not matching the route. Server Components cannot write cookies, so without it nothing refreshes the session. Check the matcher at the bottom of the file.

If it only happens on the callback, the client there is bound to next/headers rather than to the response. That mutation does not survive a redirect.

Checkout returns 503

STRIPE_SECRET_KEY is missing. That is deliberate: the app runs without Stripe so you can build before you bill.

"Expired API Key provided"

You activated live mode, which invalidates the existing test keys. Copy the new test keys from the dashboard.

The payment worked but nothing happened

Look at the Stripe dashboard's event log, not yours. It shows the response your webhook returned.

  • 400: signature mismatch. The secret in your environment belongs to a different endpoint.
  • 503: STRIPE_WEBHOOK_SECRET was not set when the process booted. Set it and redeploy; a running process will not pick it up.
  • 200 but nothing in the database: the event type is not enabled on the endpoint.

Every route returns 500 and the log says nothing

An environment variable is set to an empty string. ?? does not fall back on "", so new URL("/x", "") throws, and in the root layout that takes every page with it. Delete the variable rather than blanking it.

A NEXT_PUBLIC variable is undefined in the browser

It is marked Sensitive on Vercel, which means it is not inlined into the bundle. Change it to Encrypted and redeploy.

Borders are black and I never asked for black

You used a colour class whose token is not declared in @theme. Tailwind emits nothing, and border falls back to currentColor. Declare the token. Check the computed style rather than the screenshot; this one is easy to look at and not see.

Copy shows {name} literally

Single braces. The message format wants {{name}}, and a single-braced placeholder compiles with no warning. See Internationalisation.

A message key exists but is undefined

It has an underscore. _ is the context separator, so meta_title compiles as a variant of meta. Rename to camelCase.

The page is wider than the phone

Almost always a one-column grid sizing to max-content. Add grid-cols-1. The next most common is a flex child without min-w-0, which will not shrink below its content.

A form silently does nothing

Look for a router.refresh() firing near it. A navigation during a refresh leaves the router holding a Server Components render with nowhere to go, and the page it lands on can stop hydrating. React reports it as minified error #441, which says nothing useful in production.

An animated element ignores its transform

Motion owns transform on any element it animates. A style={{ transform }} on the same element is discarded. Animate the value instead, or wrap it.

Still stuck

Email hello@tryshipnow.com with what you expected, what happened, and the request id if there is one. A person reads it.

Something wrong or missing on this page? Tell us.