Skip to content

Troubleshooting

Find your symptom, then its fix. Each message RoutingCat prints is explained in the messages reference, and npx routingcat doctor, read check by check, names most of them.

init stops

init says Do this
Next.js is below 16, or the app has no app/ folder Upgrading Next.js is your call. RoutingCat routes App Router pages, which live in an app/ folder.
An old middleware.ts Rename it to proxy.ts with Next.js’s codemod, npx @next/codemod@canary middleware-to-proxy ., then run init again.
The folder isn’t linked to Vercel, or the Vercel CLI is signed out Run npx vercel link or npx vercel login, then init again.
No Next.js app, several apps, or Next.js not installed Install the app’s packages, then run init in the app’s own folder.
Installing the package failed Install routingcat yourself, then run init again.
The sign-in isn’t approved yet, with exit code 3 Approve the link, then run init again: it continues where it stopped.
The Vercel project belongs to a site you’re not a member of Ask that site’s owner to add you.
A file is too unusual to edit init prints the exact edit: make it, then run npx routingcat doctor, which checks it.

Running init again is always safe: it does what’s missing and never overwrites your edits.

The build registers nothing

A build that registered prints RoutingCat’s receipt in its log, starting routingcat LIVE, NOT LIVE or registered. Without it, the deployment shows your defaults and records nothing, conversions included. The build log says why:

The build log says Do this
No Vercel token and no deploy key On Vercel, turn on Settings → Security → Secure backend access with OIDC federation, then redeploy. Outside Vercel, set ROUTINGCAT_DEPLOY_KEY, from npx routingcat keys deploy --branch <production branch>.
RoutingCat can’t be reached Redeploy once it’s back.
The build token was refused Check ROUTINGCAT_DEPLOY_KEY, or that the Vercel project is still bound to your site.
The Vercel project is bound to another site Make site in routingcat.config.ts the project’s site.
No routingcat.config.ts Run npx routingcat init.
A local build Nothing: local builds never register.

Once a production build registers, its deployment registers at its first request. If none has 10 minutes later, open your site; if it still doesn’t register, check that proxy.ts exports proxy(…) from routingcat/next/proxy.

Pages show no decisions

A decision is the proxy’s choice of a visitor’s variants on a routed page. doctor checks each page’s first one.

  • The proxy didn’t run (the proxy did not run). proxy.ts must export proxy(…) from routingcat/next/proxy and keep RoutingCat’s matcher entry.
  • The page isn’t live yet. Only a production deploy makes a page live, and for about 2 minutes after its first one, the page shows its defaults and records arrivals only.
  • Routing is off. The build log’s receipt says so; npx routingcat set routing=on turns it back on. When your plan turned it off, past Hobby’s visitors a second month running or at Pro’s cap, upgrade or raise the cap instead.
  • Routing waits for a card. On Hobby, it starts once the site’s owner has a card on file: see Routing waits for a card.
  • A slot has one variant. Nothing is routed there until you add a second.
  • A cache in front of Vercel serves the page (a cache in front of Vercel). Stop caching routed pages’ HTML there: Run it in production.
  • The proxy lost access (no records from the proxy). Redeploy, which mints a fresh credential.
  • Decisions come, but no render beacon. Add <RoutingCat /> to the root layout. In your own browser, an ad blocker also stops it.

Routing waits for a card

On Hobby, routing starts once the site’s owner has a card on file, and nothing is charged. Until then, every visitor sees your defaults, and:

The owner adds a card in the dashboard’s Settings → Billing, with nothing charged, or starts Pro’s 14-day trial. Routing starts within about 2 minutes, with no new deploy. A member asks the owner. See Add a card to start routing.

A variant never shows

  • Your browser keeps its variants for the whole visit, 7 days by default, and may be in the control, the 10% who always see the defaults. To see a variant, add ?rc=hero:oneclick in development, or use a preview link in production: Change, preview and deploy.
  • It’s paused or retired. npx routingcat show home/hero:oneclick says so, and npx routingcat resume home/hero:oneclick brings it back.
  • The plan holds it. On Hobby, past the 10 live variants across the owner’s sites, a variant is registered and not served: see A variant is held.
  • It’s new, or routing favors others. A new variant starts on a limited share, and routing serves most what is likely best, though the random slice shows every variant now and then. show gives its share.
  • It was added during a visit. A slot added mid-visit shows its default to that visitor until their next visit.
  • Its build failed after registering (a build that failed after registering). Visitors keep the previous version: fix the build and redeploy, or revert the page.
  • Browsers report it shown less often than the slot’s other variants (for a smaller share of the page loads it was picked for). Check that it renders as fast as they do.

A variant is held

On Hobby, the sites you own serve at most 10 live variants together, the slots’ defaults not counted. A deploy or an act past them still succeeds, and each variant past the 10th is held: registered, and not served. The build log names it after its first line, status reads held on its row, and the dashboard marks it “Held by the plan”.

To put it live, either:

  • upgrade to Pro in Settings → Billing, for every site you own, which allows up to 100 live variants a page;
  • or retire or pause a live variant on any of your sites, which frees room.

Held variants then go live in the order they were declared, within about 2 minutes, with no new deploy. See Go past Hobby’s 10 live variants.

Conversions don’t join

Track conversions explains the tracking line of status. The messages behind it:

The control’s share is off

status raises the control check when the control’s share of new visitors departs from its setting, which can bias the measured gain. Check that page for a cache, or a proxy matcher that skips it for some visitors.

A page shows a hydration mismatch

A layout above a static routed page that reads usePathname() can make the page’s prerendered variants mismatch at hydration. Read the pathname after the component mounts, as Build a page shows.

What happens Do this
preview says the production deployment doesn’t carry the version Deploy it to production first.
preview says no deployment serving it has registered yet Right after a deploy, open your site, then run preview again. If the build failed after registering, deploy again.
preview says the page has no path to preview Pass one: --path /pricing.
preview refuses variants of several pages, or several of one slot Preview one page at a time, one variant per slot.
The page opens without the preview badge The link is valid for one hour: make a new one.
The badge names another variant The badge reads what the page shows. Right after a deploy, a new server instance can serve the page before it knows the variant: reload a few seconds later.

To end a preview, follow the badge’s link.

Run commands in a sandbox

Coding agents often run commands in a sandbox, as Work with your coding agent explains:

  • No network, exit code 4: allow network access for the command, or ask the person to run it.
  • The sandbox can’t keep a sign-in, exit code 3: run npx routingcat login in your own terminal, then the command again.
  • A sign-in link is waiting, exit code 3: give the link to the person, and once they approve, run the same command again.
  • doctor --wait runs up to 5 minutes: give it a 6-minute timeout, or run it in the background.

Read doctor check by check

npx routingcat doctor reads your project, your sign-in, your site’s records and one request to your production page, and changes nothing. That request is recorded as an arrival, flagged as RoutingCat’s own and kept out of results. After a deploy, --wait waits up to 5 minutes, printing each check as it passes, and stops early when only a person can move the rest.

$ routingcat doctor
cartwheel · production
✓ build registered ch_01m5ez85j0f5vbyqqqdja6wj31 · objective signup · outcomes purchase 10:14:00
✓ deployment registered dp_01m5ez4gc0fgzvqarjyjver1mr · commit 87299c7 · routingcat 1.0.0 10:16:40
✓ runtime Node.js 22.18.0, as dp_01m5ez4gc0fgzvqarjyjver1mr reports it
✗ proxy on / https://cartwheel.fit/ answered without RoutingCat's visitor cookie, rc_vid, so the proxy did not run on /: visitors there get your defaults, and their visits are not recorded. proxy.ts must export proxy(…) from routingcat/next/proxy and keep RoutingCat's matcher entry. (D9)
✓ /_rc reaches the collector 10:30:00
✓ records ingest.routingcat.com accepts them from https://cartwheel.fit
… first arrival the pulse shows arrivals within about a minute
… signup no event yet: the first real one passes, a visitor's or yours; to confirm now, sign up once on cartwheel.fit, then run doctor again
✓ card on file Visa •••• 4242
6 of 9 passed · 1 failed · 1 waits for a person · 1 still waiting: run doctor --wait (exit 1)
Check Passes when Otherwise
Your files, shown only when one fails Next.js 16 or later with the App Router, init’s edits, the site’s public key, and an up-to-date skill Next.js, an edit to make, the wrong public key, the skill
build registered A production build registered, with the objective and outcomes it declares Waits for a production deploy
deployment registered The deployment serving that build registered at its first request No deployment registered after 10 minutes
runtime The production deployment reports what runs the proxy: Node.js, or Bun where vercel.json’s bunVersion chooses it Nothing: the line says which
proxy on / Your production page set rc_vid The proxy did not run. If Vercel’s firewall challenges the check’s request, doctor reads the pulse instead.
/_rc Your site’s /_rc path reaches RoutingCat /_rc is missing
records RoutingCat’s edge accepts your pages’ records from your production address The edge refuses the address: add your domain with npx routingcat domains add
first arrival The pulse shows an arrival, often the check’s own request Waits about a minute
The objective, by its name A first conversion arrived No event yet: waits for the first real conversion, a visitor’s or your own, and nothing else waits on it
card on file, on Hobby The site’s owner has a card on file, shown by its brand and last 4 digits Waits for the owner to add one, at the link it gives: routing waits for a card
page live, first decision, first render beacon Each routed page is live, decided, and shown in a browser Waits for a visit; no render beacon, or a cache in front of Vercel
server key, location headers, shown only when one fails The preview key used in production, Cloudflare without its location headers

Lines marked · are information and need nothing: conversions with no routed visit yet, an undeclared name, and, run in your project, whether AGENTS.md has the note for coding agents, which is your choice.

doctor exits with 0 when every check passed, 1 when one failed, 3 when one is still waiting, and 4 when the network blocks it.

Next