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
It recognizes no project here Run it in your site’s own folder, where your templates are.
Several sites are here Run it in the folder of the site to set up.
It can’t tell where the site deploys or is served Run it again with --host none, for a host that runs nothing of RoutingCat’s.
It needs your production address Run it again with --origin https://www.example.com.
The sign-in isn’t approved yet, with exit code 3 Approve the link, then run init again: it continues where it stopped.
A file is too unusual to edit, such as a layout among several init prints the exact edit: make it, then run npx routingcat doctor, which checks it.
npx can’t run the version the config pins, with exit code 2 Check your network, and the registry npm config get registry prints, then run the same command again; or move the site to the version you ran, as the message says.

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

A push registers nothing

A push that registered prints RoutingCat’s receipt last, starting routingcat LIVE, NOT LIVE or registered. Without it, a deploy that changed your templates leaves your pages on their defaults, recording no decision. The push says why:

The push says Do this
It registered nothing, with no credential here On your machine, that is expected: commit what it changed, and right after your deploy, register production with npx routingcat push --env production, or in your CI or your host’s deploy script. In GitHub Actions, link the repository with npx routingcat link github and give the job permissions: id-token: write; in any CI or deploy script, set ROUTINGCAT_DEPLOY_KEY, from npx routingcat keys deploy --branch <production branch>.
Nothing was pushed: the plan waits for the person, with exit code 3 Show the person the plan it printed. Once they agree, run it again with --confirm and the digest it gave.
The confirmed plan has changed since Your templates or production changed: show the person the new plan, and confirm that one.
The credential was refused, with exit code 1 The reason names it. A production deploy key proves production only for pushes of its branch, which RoutingCat reads from the CI’s own variables on GitHub Actions, GitLab, Bitbucket, CircleCI, Jenkins’ multibranch pipelines, Azure Pipelines, Buildkite, Cloudflare’s Workers Builds or Pages, Netlify and Vercel, and elsewhere from ROUTINGCAT_BRANCH: in any other CI or a deploy script, set it to the branch being deployed. Inside a CI RoutingCat reads, the variable doesn’t apply: a Jenkins job that isn’t a multibranch pipeline, or Azure Pipelines over TFVC, names no branch, so run the push from a multibranch pipeline, or from a Git repository. A run of a pull request, a tag or another branch takes the preview key, from npx routingcat keys deploy --env preview. A GitHub token is refused from a repository not linked to the site, or whose link expired: run npx routingcat link github, then the workflow again.
npx can’t run the version the config pins, with exit code 2 Check the network, and the registry npm config get registry prints, then run the same command again.
The site registers from its build The site is bound to a host whose build registers it: deploy there. A site created for that host, then moved to decide in the page, stays bound to it, and registers with the deploy key alone, in your CI or your host’s deploy script.
RoutingCat can’t be reached, with exit code 4 Run the push again once it is back.

The GitHub link waits for a run, or expired. npx routingcat link github and doctor say where it stands. A pending link waits for push to run in a workflow of that repository whose job has permissions: id-token: write, before the time it names. Once it has expired, run npx routingcat link github again, then such a workflow, or npx routingcat unlink github to keep the deploy key alone.

push --check fails in CI when a template lacks a stamp or the partial is out of date: run npx routingcat push in your repository, commit what it changes, and run the workflow again.

push and plan refuse slot markup they can’t read or that breaks its rules, each with the file, the line and the fix: markup they can’t read, the slot’s grammar, a slot the browser would move, what a hidden variant holds, and templates and config that disagree. Build a page gives each rule. Here, a hidden variant holds a script:

$ routingcat push
✗ layouts/index.html:9: home/hero:studio holds a script that runs, or structured data that search engines read, even while the variant is hidden. Move it out of the variant. (D69, exit 1)

Once a production push registers its changes, it registers your deployment last. If no deployment has registered since, run the push again on the same templates, which registers it or says why it can’t.

Pages show no decisions

A decision is a visitor’s browser picking their variants on a routed page. doctor checks each page’s first one.

  • The page doesn’t carry the head partial, or carries it out of place. Include the partial first in each layout’s <head>, after the charset and viewport tags.
  • The page isn’t live yet. Only a production push makes a page live, and until its routing data is published, within about 2 minutes, the page shows its defaults.
  • The page’s head partial names templates no push registered yet (a partial no push registered). From a deploy that changed your templates until about 2 minutes after its push, your pages show your defaults and record no decision: register each deploy right after it, as Change, preview and deploy explains.
  • Routing is off. The push’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.
  • The page’s routing data is over its 128 KB. Every visitor gets its defaults until a push brings it under: retire variants, or turn personalization off for a slot.
  • The page’s Content Security Policy blocks RoutingCat. Give the head partial’s script tags the page’s nonce in your template, which push keeps, or add the core’s hash that doctor names, which an upgrade of routingcat can change; then add each other source it names. Run it in production gives the whole policy.
  • Records can’t reach RoutingCat: it doesn’t accept them from your domain, so add the domain with npx routingcat domains add; or the pages have sent nothing for hours, which doctor traces to the page.
  • Cloudflare runs RoutingCat’s script late, through Rocket Loader, or puts Zaraz first: see Run it in production.
  • Decisions come, but no render beacon. RoutingCat’s post part doesn’t run on the page: it doesn’t load, or a policy blocks it. 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 push. 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:learns in development, or use a preview link in production: Change, preview and deploy.
  • It’s paused or retired. npx routingcat show home/hero:learns says so, and npx routingcat resume home/hero:learns brings it back.
  • The plan holds it. On Hobby, past the account’s 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.
  • Your deployed pages don’t carry it. A variant pushed but not deployed waits for the deploy, since each page shows only the variants its own head partial lists.
  • Your served HTML differs from your templates, as when a minifier drops data-rc-* attributes or hidden. Build and deploy from the templates push stamped.
  • A first view waited past its deadline. That visitor keeps the defaults on that page for the rest of the visit: see Expect a first view to wait.
  • 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, an account serves at most 10 live variants, across all of its owner’s sites, the slots’ defaults not counted. A push or an act past them still succeeds, and each variant past the 10th is held: registered, and not served. The push names it after its receipt, 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 push. See Go past Hobby’s 10 live variants.

Conversions don’t join

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

Results leave decisions out

  • Decisions that fail replay are left out of every result. For unregistered_deployment, your pages ran a core that decided under templates no push had registered: upgrade the version your config pins, whose core shows such a page’s defaults and records nothing until its push, and run push --check before every deploy and push right after it. doctor names a page whose partial no push registered. The other reasons are RoutingCat’s to fix.
  • Decisions whose record never arrived are left out too: make sure nothing on your pages or in front of them, such as a Content Security Policy or a proxy, blocks the page’s requests to RoutingCat.
What happens Do this
preview says the production deployment doesn’t carry the version Push and deploy it to production first.
preview says no deployment that includes it has registered yet Run the production push again on the same templates, which registers the deployment last, then preview.
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.

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.
  • A production push from the machine waits for the person, exit code 3: show them the plan, and run it with --confirm once they agree.
  • doctor --wait waits for a visit a person makes, up to 5 minutes: give the person the page it names to open, and give the call 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 your production pages as served at each page’s url, and changes nothing. Your pages decide only in a browser, so doctor’s requests record no visit: until a first arrival comes, it names a page to open in a browser, and --wait waits up to 5 minutes for that visit. Set up RoutingCat shows a run where every check passes. Here, the page’s policy runs no inline script but by nonce or hash:

$ routingcat doctor
lumen · production
✓ build registered ch_01m3yfrpt0ewpateq9yrq61xkb · objective signup · outcomes waitlist 14:19:52
✓ head partial 1 page: first in <head>, core 1.0.0, manifest 47a096ddb5c9… registered
✓ post part rt/1/post/1.0.4.js loads, its integrity checked
✗ policy https://www.lumen.com/'s Content Security Policy runs no inline script but by nonce or hash, and RoutingCat's core carries neither, so the page never decides: visitors get your defaults, and their visits are not recorded. Give the script tags of resources/views/routingcat-head.blade.php the page's nonce in your template, which routingcat push keeps, or add 'sha256-ufFiB8WxqAPeqL6gM1yjrNQwjPr6NxbBkJftA/62vQI=' to script-src, the core's hash, which an upgrade of routingcat can change. (D92)
✓ records ingest.routingcat.com accepts them from https://www.lumen.com
✓ markup no slot on these pages yet
✓ first arrival arrivals in the pulse, last 14:39:18 14:39:18
✓ signup 2 events 14:33:59 · server · identify 14:32:05 14:33:59
✓ card on file Visa •••• 4242
· AGENTS.md has no RoutingCat note, so coding agents may skip the skill unless a request matches it; if the person wants the note, run npx routingcat init --agents-md
8 of 9 passed · 1 failed (exit 1)
Check Passes when Otherwise
Your files, shown only when one fails The config valid, with the site’s public key; your templates’ stamps and partial as push writes them; the partial’s include; the server helpers your config declares, and their registration; on Laravel, rc_vid left out of the cookie encryption; an up-to-date skill The wrong public key, stamps or a partial out of date, an edit to make, the skill
build registered A production push registered, with the objective and outcomes your config declares Waits for a production push
GitHub link, on a linked site A workflow run of the repository proved the link It waits, or it expired
head partial Each page carries it, readable, first in <head>, and naming templates a push registered Before the site’s first deploy, waits for that deploy and its push. Then the partial, and one no push registered yet, which waits for that push, then fails at the end of --wait; Zaraz placed before it
bundle RoutingCat’s CDN has routing data for each routed page, for a core it hasn’t turned off, listing the templates your pages name Waits for a production push that makes the page live, and after a push, about 2 minutes for routing data that lists its templates; routing data that doesn’t list them, a core RoutingCat turned off
post part It loads as pinned, its integrity checked The post part doesn’t load
policy The page’s Content Security Policy lets RoutingCat run, apply and record The source to add
records RoutingCat’s edge accepts records from your production address The domain to add
markup Each page’s slots, as served, match your templates, with registered hashes Served markup that differs
server helpers, where your config declares them Each page sets the cookies they set Helpers that don’t run
Cloudflare’s features, behind Cloudflare Rocket Loader leaves RoutingCat’s core to run first Rocket Loader running it late
first arrival A browser’s visit arrived, in the pulse Waits for a person to open the page it names
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
server key, browser bundle, shown only when one fails The preview server key used in production, a page over its 128 KB of routing data

Lines marked · are information and need nothing: a newer core or post part than your pages run, 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