Messages
Every warning and error RoutingCat shows carries an id, such as D14: in the text of the command and the build log, after the message, and in --json, as error.id or each warning’s id. Each id below is an anchor: messages.md#d14.
- Severity: an error means serving, tracking or the measured gain cannot be trusted until it is fixed. Information needs nothing. Every other message is a warning.
- Where it shows: the commands, the build log or the dashboard that report it.
pushruns in your build, so its messages show in the build log. - Forms: a message has one or more forms, each with its code, as
--jsongives it, and its text. Words in braces, such as{page}, are filled in. The exit code is the one the command ends with.
Diagnostics
What the command, the build and the dashboard find in your install, your tracking and your pages.
D1
Warning, shown in every command. No sign-in on this machine; in a Shopify theme’s or a Hydrogen storefront’s folder, which pairs with its store’s site instead, no pairing with that site.
not_signed_in:You are not signed in to RoutingCat on this machine. Run npx routingcat login.not_paired:This machine is not paired with the store's RoutingCat site. Run npx routingcat init in the theme's or storefront's folder, then enter the code it prints in the RoutingCat app in your Shopify admin.
Fix: Run npx routingcat login, then approve the sign-in link in your browser. In a Shopify theme’s or a Hydrogen storefront’s folder, run npx routingcat init there instead, and enter the code it prints in the RoutingCat app in your Shopify admin.
D2
Warning, shown in init and doctor. Next.js below 16.2.6, the first release that fixes the proxy’s authorization bypasses and its cache-poisoned redirects of 16.0 to 16.2.5, or no app/ folder.
next_unsupported:This app has Next.js {version}, and RoutingCat needs Next.js 16 or later with the App Router. Upgrading is your call: npx @next/codemod@canary upgrade latest.next_insecure:This app has Next.js {version}, and RoutingCat needs 16.2.6 or later: Next.js 16.0 to 16.2.5 let a request bypass the proxy's authorization and let a cache keep one visitor's proxy redirect for others. Upgrading is your call: npx @next/codemod@canary upgrade latest.no_app_router:No app/ folder, so this is a Pages Router app, and RoutingCat routes App Router pages. Moving pages to the App Router is your call; then run npx routingcat init again.
Fix: Upgrading Next.js is your call: npx @next/codemod@canary upgrade latest. RoutingCat runs in your proxy, so it needs Next.js 16.2.6 or later, and routes App Router pages, which live in an app/ folder.
D4
Warning, shown in init. The folder is not linked to a Vercel project, or the Vercel CLI is missing or signed out.
vercel_not_linked:This folder is not linked to a Vercel project, which init ties your site to. Run npx vercel link --yes --project <name>, then npx routingcat init again.vercel_signed_out, exit 3:The Vercel CLI is not signed in, so init cannot tie your site to your Vercel project. Run npx vercel login, then npx routingcat init again.
Fix: Run npx vercel link --yes --project <name>, or npx vercel login, then npx routingcat init again. Signing in to Vercel needs you, not your agent.
D5
Warning, shown in the build log. A build with no credential, no Vercel or GitHub Actions OIDC token and no deploy key, its fix worded for the CI that runs it: Vercel’s build, a GitHub workflow, Cloudflare’s builds or any other, a Cloudflare or Oxygen project’s build taking the deploy key’s words in any CI, since only that key proves it; or a build that cannot reach RoutingCat.
no_build_credential:routingcat: no Vercel or GitHub Actions OIDC token and no ROUTINGCAT_DEPLOY_KEY, so this build cannot identify itself to RoutingCat: it registers nothing, and visitors get your defaults. On Vercel, turn on Settings → Security → Secure backend access with OIDC federation, then redeploy.github_no_build_credential:routingcat: no Vercel or GitHub Actions OIDC token and no ROUTINGCAT_DEPLOY_KEY, so this build cannot identify itself to RoutingCat: it registers nothing, and visitors get your defaults. In a GitHub workflow, give the job permissions: id-token: write.cloudflare_no_build_credential:routingcat: no Vercel or GitHub Actions OIDC token and no ROUTINGCAT_DEPLOY_KEY, so this build cannot identify itself to RoutingCat: it registers nothing, and visitors get your defaults. Run npx routingcat keys deploy --branch <your production branch>, set what it prints as the build variable ROUTINGCAT_DEPLOY_KEY in Cloudflare's build settings, then redeploy.ci_no_build_credential:routingcat: no Vercel or GitHub Actions OIDC token and no ROUTINGCAT_DEPLOY_KEY, so this build cannot identify itself to RoutingCat: it registers nothing, and visitors get your defaults. Run npx routingcat keys deploy --branch <your production branch>, set what it prints as the secret ROUTINGCAT_DEPLOY_KEY in this build's CI, then redeploy.api_unreachable:routingcat: cannot reach RoutingCat at {host}, so this build registers nothing and visitors get your defaults.
Fix: The build still ships, but registers nothing, so visitors get your defaults. On Vercel, turn on Settings → Security → Secure backend access with OIDC federation, then redeploy. In a GitHub workflow of the repository that holds the site, give the job permissions: id-token: write, and the build proves itself with GitHub’s OIDC token. Any other build, and a Cloudflare or Oxygen project’s wherever it runs, needs ROUTINGCAT_DEPLOY_KEY, from npx routingcat keys deploy --branch <production branch>: in Cloudflare’s builds, as a build variable in their settings; elsewhere, as a secret of the CI that runs it. If RoutingCat was unreachable, redeploy later.
D8
Warning, shown in plan and push. A declaration uses when, requires, excludes or targeting, or a page is keyed site.
unsupported_capability, exit 1:{address} uses {field} ({capability}). Remove it, and RoutingCat accepts the declaration; nothing live changed.
Fix: Remove the field, or rename the page keyed site. Nothing live changed.
D9
Warning, shown in doctor. The proxy did not run on a page.
proxy_not_running:{url} answered without RoutingCat's visitor cookie, rc_vid, so the proxy did not run on {path}: 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.
Fix: proxy.ts must export proxy(…) from routingcat/next/proxy and keep RoutingCat’s matcher entry, '/((?!_next/|_rc/|api/|.*\\.(?!rsc$)[a-z0-9]+$).*)'. If Vercel’s firewall challenged the request, doctor checks nothing there and reads the live activity instead.
D10
Warning, shown in status. A build failed after registering its changes.
build_failed_after_push:A build made {address} live, but failed after registering, so it never deployed: visitors still see the previous version, and are recorded as seeing it. Fix the build and redeploy, or run routingcat revert {page}.
Fix: Visitors keep the previous version until a build that carries the new one deploys. Fix the build and redeploy, or return the page to what it served before with npx routingcat revert <page>.
D11
Error, shown in doctor and status. No deployment has registered since a build registered a change.
deployment_not_registered:Your deployment from {ago} ago has not registered, so visitors may not be getting its changes yet. A deployment registers on its first request: open {url} or run routingcat doctor. If it still does not, check that proxy.ts exports proxy(…) from routingcat/next/proxy.
Fix: A deployment registers at its first request: open the site, or run npx routingcat doctor. If it still does not register, check that proxy.ts exports proxy(…) from routingcat/next/proxy.
D12
Warning, shown in status. A deployment serves content that matches no registered version.
observed_version:Your production deployment serves {address} with content that matches no registered version: its build did not register (see D5). Visitors see it as deployed, and RoutingCat records it as unregistered until the next production deploy registers it.
Fix: Its build did not register, for one of the reasons D5 lists: fix that, then deploy. The warning clears at the next production deploy that registers.
D13
Warning, shown in doctor and status. Routed page loads without render beacons, a server’s decisions or the browser runtime’s, each on its own; a server’s in the form of the framework it runs, by the host block its newest production deployment registered.
no_render_beacon:{page}: the proxy picked variants for {decisions} page loads in the last hour, but no browser reported showing one (no render beacon). Visitors still get their variants, but visits from links on your site are not counted. Add <RoutingCat /> to {layout}; in your own browser, an ad blocker also stops it.nuxt_no_render_beacon:{page}: RoutingCat picked variants for {decisions} page loads in the last hour, but no browser reported showing one (no render beacon). Visitors still get their variants, but visits from links on your site are not counted. Keep routingcat/nuxt in nuxt.config's modules, whose plugin sends it; in your own browser, an ad blocker also stops it.astro_no_render_beacon:{page}: RoutingCat picked variants for {decisions} page loads in the last hour, but no browser reported showing one (no render beacon). Visitors still get their variants, but visits from links on your site are not counted. Add <RoutingCat /> from routingcat/astro/components to your layout's <head>; in your own browser, an ad blocker also stops it.react_router_no_render_beacon:{page}: RoutingCat picked variants for {decisions} page loads in the last hour, but no browser reported showing one (no render beacon). Visitors still get their variants, but visits from links on your site are not counted. Add <RoutingCatTracker /> from routingcat/react to app/root.tsx; in your own browser, an ad blocker also stops it.html_no_render_beacon:{page}: RoutingCat picked variants for {decisions} page loads in the last hour, but no browser reported showing one (no render beacon). Visitors still get their variants, but visits from links on your site are not counted. Keep RoutingCat's tracker script in the page's <head>, where its head partial, or nuxt.config's head, puts it, which routingcat doctor checks; in your own browser, an ad blocker also stops it.browser_no_render_beacon:{page}: browsers picked variants for {decisions} page loads in the last hour, but none reported showing one (no render beacon): RoutingCat's post part does not run on the page. Visitors still get their variants, but nothing reports what they saw or did there. Run routingcat doctor, which checks what the page loads; in your own browser, an ad blocker also stops it.
Fix: The render beacon is the browser’s report that the page showed. On Next.js, <RoutingCat /> from routingcat/next in the root layout sends it; on Nuxt, the routingcat/nuxt module; on Astro, <RoutingCat /> from routingcat/astro/components in the layout’s head; on React Router, <RoutingCatTracker /> from routingcat/react in the root route; on a static or templated site, the tracker script of RoutingCat’s head partial, or of nuxt.config’s head on Nuxt 2; where browsers decide, RoutingCat’s post part, which npx routingcat doctor checks. In your own browser, an ad blocker also stops it.
D14
Warning, shown in doctor. No event for the objective yet.
no_objective_event:No {event} event yet: the first real one on your production site, a visitor's or your own, passes this check, and nothing else waits on it. Confirming your tracking now is your call: {trigger} on {host}, then run routingcat doctor again. If {occurrence} happens in another app, track it from there.
Fix: The check passes with the first real conversion on the production site, a visitor’s or your own, and nothing else waits on it. Confirming your tracking now is your call: convert once yourself, as a visitor would, then run npx routingcat doctor again. If the conversion happens in another app or backend, track it from there.
D15
Information, shown in doctor and status. Conversions whose visitor never reached a routed page.
no_routed_visit:{event} events are recorded; they are credited to variants once their visitors see a routed page.
Fix: Nothing to fix: the conversions are credited to variants once their visitors see a routed page.
D16
Warning, shown in status. Far more render beacons than routed page loads, on pages a server decides, in the form of the host its newest production deployment registered: the browser runtime decides on every view, whatever caches the page.
html_cached:{page}: browsers showed it {beacons} times in the last hour, but the proxy picked variants for only {decisions} page loads, so a cache in front of Vercel serves {path} without the proxy: visitors get a cached copy instead of their own variants, and most of their visits are not recorded. Stop caching HTML for routed pages.middleware_html_cached:{page}: browsers showed it {beacons} times in the last hour, but the middleware picked variants for only {decisions} page loads, so a cache in front of Vercel serves {path} without the middleware: visitors get a cached copy instead of their own variants, and most of their visits are not recorded. Stop caching HTML for routed pages.worker_html_cached:{page}: browsers showed it {beacons} times in the last hour, but the Worker picked variants for only {decisions} page loads, so a cache in front of the Worker serves {path} without it: visitors get a cached copy instead of their own variants, and most of their visits are not recorded. Stop caching HTML for routed pages before the Worker runs.
Fix: A cache serves the page without running RoutingCat: in front of Vercel, it skips the proxy or the middleware; on Cloudflare, Workers Cache or a cache rule in front of the Worker skips it. Stop caching HTML for routed pages.
D19
Warning, shown in status. Far more routed page loads than render beacons, a server’s decisions or the browser runtime’s, each on its own, a server’s in the words of what decides there, as D16’s, or a variant that browsers report as shown less often than the slot’s others.
beacons_below_decisions:{page}: the proxy picked variants for {decisions} page loads in the last hour, but browsers reported showing only {beacons}: likely automated traffic, or a blocked beacon. Visitors still get their variants, and known crawlers are already flagged.middleware_beacons_below_decisions:{page}: the middleware picked variants for {decisions} page loads in the last hour, but browsers reported showing only {beacons}: likely automated traffic, or a blocked beacon. Visitors still get their variants, and known crawlers are already flagged.worker_beacons_below_decisions:{page}: the Worker picked variants for {decisions} page loads in the last hour, but browsers reported showing only {beacons}: likely automated traffic, or a blocked beacon. Visitors still get their variants, and known crawlers are already flagged.browser_beacons_below_decisions:{page}: browsers picked variants for {decisions} page loads in the last hour, but reported showing only {beacons}: likely automated traffic, or a blocked beacon. Visitors still get their variants, and known crawlers are already flagged.confirmation_differs:{address}: browsers reported it shown for {share}% of the page loads it was picked for, against {others}% for the slot's other variants, so some visitors may not see it. Check that it renders as fast as they do.
Fix: Missing render beacons come from automated traffic, or from a beacon blocked in the browser; known crawlers are flagged and need nothing. For a variant browsers report as shown less often than the others, check that it renders as fast as they do.
D20
Error, shown in status and the dashboard. No decision or arrival recorded for hours by the server that decides, the proxy, a host’s middleware or a Worker, or by browsers on the pages they decide, each checked on its own.
no_records:Your proxy has recorded nothing for {hours} h (last at {last} UTC). If the site has traffic, the proxy has lost access to RoutingCat: visitors still get your pages, but nothing is being recorded. Redeploy to give it a fresh credential.middleware_no_records:Your middleware has recorded nothing for {hours} h (last at {last} UTC). If the site has traffic, the middleware has lost access to RoutingCat: visitors still get your pages, but nothing is being recorded. Redeploy to give it a fresh credential.worker_no_records:Your Worker has recorded nothing for {hours} h (last at {last} UTC). If the site has traffic, the Worker has lost access to RoutingCat: visitors still get your pages, but nothing is being recorded. Redeploy to give it a fresh credential.script_no_records:Your pages have sent RoutingCat no records for {hours} h (last at {last} UTC). If the site has traffic, its pages no longer run RoutingCat's head partial, or their records cannot reach RoutingCat: visitors may get your defaults, and nothing is being recorded. Run routingcat doctor, which checks your pages.shopify_no_records:Your store has sent RoutingCat no records for {hours} h (last at {last} UTC). If it has traffic, RoutingCat's app embed is off in its published theme: visitors see your theme without RoutingCat, every copy of a tested section included, and nothing is being recorded. Turn RoutingCat on in the theme from the app's Home page in your Shopify admin.cloudflare_worker_no_records:Your Worker has recorded nothing for {hours} h (last at {last} UTC). If the site has traffic, the Worker has lost access to RoutingCat, or Cloudflare stopped running it until midnight UTC, past the 100,000 requests a day of the Workers Free plan: nothing is being recorded. Redeploy to give it a fresh credential, or move to Workers Paid, which RoutingCat needs.pages_no_records:Your Pages middleware has recorded nothing for {hours} h (last at {last} UTC). If the site has traffic, the middleware has lost access to RoutingCat, or Cloudflare stopped running it until midnight UTC, past the 100,000 requests a day of the Workers Free plan, which Pages Functions count toward: nothing is being recorded. Redeploy to give it a fresh credential, or move to Workers Paid, which RoutingCat needs.pages_worker_no_records:Your Worker has recorded nothing for {hours} h (last at {last} UTC). If the site has traffic, the Worker has lost access to RoutingCat, or Cloudflare stopped running it until midnight UTC, past the 100,000 requests a day of the Workers Free plan, which Pages Functions count toward: nothing is being recorded. Redeploy to give it a fresh credential, or move to Workers Paid, which RoutingCat needs.
Fix: If the site has traffic, the proxy, middleware or Worker that decides has lost access: redeploy, which gives it a fresh credential; on Cloudflare’s Free plan a Worker, and a Pages project’s Functions, also stop past their daily requests, so RoutingCat needs Workers Paid. Where browsers decide, the pages no longer run RoutingCat’s head partial, or their records cannot reach RoutingCat: npx routingcat doctor checks them. On a Shopify store, RoutingCat’s app embed is off in the published theme: turn it on from the app’s Home page in the Shopify admin.
D21
Information, shown in status. A slot with one variant.
one_variant:{slot} has one variant, so nothing is routed there until you add a second.
Fix: Nothing to fix. To route the slot, add a second variant.
D23
Information, shown in the build log. The first line RoutingCat writes for a build.
live:routingcat LIVE {summary}, routing within about 2 minutes ({refs})live_unchanged:routingcat LIVE {summary}, no change ({refs})not_live:routingcat NOT LIVE preview: {summary}; production unchangednot_live_routing_off:routingcat NOT LIVE {page}: routing is off for {site}; {summary} ({refs})not_live_card:routingcat NOT LIVE routing waits for a card on file: add one at {link}, nothing chargednot_live_denied:routingcat NOT LIVE {page}: this build is not allowed to make changes live; {summary} ({refs})registered:routingcat registered {change} · {declarations} · no page routed yetregistered_unchanged:routingcat registered, no change · {declarations} · no page routed yet
Fix: Nothing to fix. LIVE: routing starts within about 2 minutes. NOT LIVE preview: a preview deploy records versions and changes nothing live. routing is off: turn it on with npx routingcat set routing=on, or, when your plan turned it off, subscribe or raise the cap in Settings, Billing. routing waits for a card on file: the site’s owner adds one at the link, nothing charged, and routing starts within about 2 minutes, with no new deploy. not allowed to make changes live: the build registered its versions, and nothing went live. registered: the objective and outcomes, with no page routed yet.
D24
Warning, shown in status. identify without a visitor id.
identify_without_visitor:An identify call on {host} arrived without the rc_vid cookie, so it linked no visitor to the account: that account's conversions may not be counted. This is often a sign-in callback posted from another site.
Fix: Often a sign-in callback posted from another site, such as Sign in with Apple’s, which arrives without the rc_vid cookie. Call routingcat.identify() on the next page load instead.
D25
Warning, shown in status. Events with neither a visitor id nor an account id.
no_key:{count} {event} events from {host} carry neither a visitor id nor an account id, so they cannot be credited to any visit.
Fix: Send each event with the visitor’s id, from the rc_vid cookie, or with an account id: visitorId or accountId in track(), visitor_id or account_id in the HTTP events API.
D26
Warning, shown in status. Events whose account ids were never linked to a visitor.
unlinked_account:{count} {event} events use account ids never linked to a visitor, so none is credited to a visit. Call identify at sign-up and at every sign-in.
Fix: Call routingcat.identify() at sign-up and at every sign-in.
D27
Error, shown in status and the dashboard. Silence: no conversions in many matured visits, where none at all is unlikely.
silence:No {event} events in {visits} visits to {page} whose outcome is known, which is unlikely if tracking works: conversions may not be counted. Is routingcat.track('{event}') still called?
Fix: Check that routingcat.track() is still called for the event. For the time it was not, record a tracking gap with npx routingcat gap, so those visits count as unknown rather than as no conversion.
D28
Error, shown in status and the dashboard. Drop: conversions fell after a deploy.
drop:{event} fell from {before} a day to {after} since {since} UTC. If the deploy live then broke tracking, conversions are not being counted: fix it and record a tracking gap.
Fix: If tracking broke, fix the routingcat.track() call, then record the time it missed: npx routingcat gap <outcome> --from <time> --to <time>, so those visits count as unknown rather than as no conversion.
D29
Warning, shown in doctor. Browser events skip the site’s /_rc path.
rc_path_missing:Browser events go to {host} directly, not through your site's /_rc path, so ad blockers can stop them: for visitors who use one, conversions tracked in the browser are not counted. Wrap your next.config export in withRoutingCat().
Fix: Wrap the next.config export in withRoutingCat(), which adds the /_rc rewrite: browser events then go through your own domain, out of reach of ad blockers that block RoutingCat’s.
D30
Warning, shown in init and login. A sign-in link not approved yet, or, in a Shopify theme’s or a Hydrogen storefront’s folder, a pairing’s code not entered yet in the Shopify admin.
sign_in_pending, exit 3:Sign in to RoutingCat: {link}. Not approved after {seconds} s. Once approved, run the same command again.pairing_pending, exit 3:Enter the code {code} in the RoutingCat app in your Shopify admin, {link}: in its Settings, or its setup guide's last step. Not entered after {seconds} s. Once entered, run the same command again.
Fix: Approve the link in your browser, or give it to the person who will; for a pairing, enter the code in the RoutingCat app in the Shopify admin. Then run the same command again.
D31
Warning, shown in every command. RoutingCat cannot be reached from here.
network_blocked, exit 4:Cannot reach {host}: {cause}. Allow network access for this command, or run it in your own terminal.
Fix: Often a coding agent’s sandbox without network access. Allow network access for the command, or run it in your own terminal.
D32
Warning, shown in init and doctor. A file too unusual for init to edit safely.
edit_printed:{file}: {reason}, so init cannot edit it safely. Make this edit yourself, then run routingcat doctor: {diff}
Fix: Make the printed edit exactly, then run npx routingcat doctor, which checks it.
D33
Warning, shown in plan and push. A routed page without an objective.
no_objective, exit 1:{page}: {count} live variants in {slot}, but no objective: routing needs a conversion to learn from. Add to {config}: objective: '{suggestion}',no_objective_json, exit 1:{page}: {count} live variants in {slot}, but no objective: routing needs a conversion to learn from. Add to routingcat.config.json: "objective": "{suggestion}",
Fix: Add the printed line to the config it names, routingcat.config.ts, a JavaScript app’s routingcat.config.mjs or a template site’s routingcat.config.json, or give the page its own objective.
D34
Warning, shown in plan and push. A routed page outside the App Router.
pages_router_page, exit 1:{route} is a Pages Router page ({file}); RoutingCat routes App Router pages only.
Fix: Route App Router pages only.
D35
Warning, shown in doctor. The installed skill is older than the package, or edited.
skill_outdated:The RoutingCat skill your coding agent reads is {skill_version}, older than the package, {package_version}. Run npx routingcat init to update it.skill_edited:The RoutingCat skill was edited here, so init leaves it as it is and does not update it.
Fix: Run npx routingcat init to update an old skill. An edited skill is kept as it is.
D36
Warning, shown in plan and push. A page, or the site, over a limit.
combinations_limit, exit 1:{page}: {count} combinations of variants ({breakdown}) on a prerendered page; the limit is {limit}. Retire variants or merge slots.combinations_warning:{page}: {count} combinations of variants ({breakdown}) on a prerendered page, more than {threshold}: each deploy builds every one as a page of its own, while the page's copies, its params' included, stay within {limit}; the limit is {limit}.variants_limit, exit 1:{page}: {count} live variants across its slots; the limit is {limit} per page. Retire variants first.slots_limit, exit 1:{page}: {count} slots; the limit is {limit} per page. Merge slots.page_size_limit, exit 1:{page}: its routing data would take {size}; the limit is {limit} per page. Retire variants or turn personalization off for a slot.site_size_limit, exit 1:{site}: its routing data would take {size}; the limit is {limit} per site. Retire variants or turn personalization off for some slots.browser_bundle_warning:{page}: its routing data for browsers would take about {size}, more than {threshold}; past {limit}, RoutingCat publishes none for the page, and every visitor gets its defaults, unrouted. Retire variants or turn personalization off for a slot.head_size_limit, exit 1:{partial}: the list of your pages, slots and variants that routingcat push writes there would take {size}; the limit is {limit}, since every page reads it before anything else. Remove from your templates the variants and slots you no longer test.
Fix: Retire variants, merge slots, or turn personalization off for a slot: routing data grows with each live variant, and with personalization. Limits and defaults lists each limit.
D37
Warning, shown in doctor. A server key from the other environment; read by a coding agent, or without a terminal, the fix asks the site’s owner, who shows the production key in their own terminal.
server_key_env:Events from {host} are sent with the preview server key, so they are left out of production results. Use the production key: npx routingcat keys server --env production.server_key_env_agent:Events from {host} are sent with the preview server key, so they are left out of production results. Ask the site's owner to run npx routingcat keys server --env production in their own terminal, and to put the key it prints in place of the preview one.
Fix: Events sent with the preview key stay out of production results. Use the production key, from npx routingcat keys server --env production.
D38
Information, shown in doctor. Events under names no objective or outcome declares, but refund and dispute, which results link to the purchases they correct.
undeclared_event:{event} events arrive, but no objective or outcome declares that name, so they are recorded and left out of results. Declare it in {config} if it matters.
Fix: They are recorded but left out of results. Declare the event as an outcome in the site’s config if it matters: routingcat.config.ts, a JavaScript app’s routingcat.config.mjs or a template site’s routingcat.config.json.
D39
Warning, shown in init. An old middleware.ts.
middleware_present:middleware.ts is deprecated in Next.js 16, and RoutingCat installs only into proxy.ts. Renaming it is your call: npx @next/codemod@canary middleware-to-proxy . then run npx routingcat init again.
Fix: Renaming it is your call: npx @next/codemod@canary middleware-to-proxy ., then npx routingcat init again.
D40
Warning, shown in plan and push. A static routed page without its wrapper route.
wrapper_missing, exit 1:{page} is a static page without its wrapper route, {wrapper}, so it cannot serve its variants. Add the wrapper that routingcat plan prints.
Fix: Add the wrapper route that npx routingcat plan prints: a static page needs it to serve its variants.
D41
Warning, shown in plan and push. The wrapper’s caching settings differ from the page’s.
wrapper_settings_differ:{wrapper} sets {setting} = {wrapper_value}, but {page_file} sets {page_value}. Copy the page's value into the wrapper: Next.js ignores settings a file re-exports.
Fix: Copy the page’s value into the wrapper, as a literal: Next.js ignores settings a file re-exports.
D42
Information, shown in plan. A layout above a static routed page that reads usePathname() during render.
use_pathname:{layout} reads usePathname(), which can cause a hydration mismatch on {route}'s prerendered variants. Read it after the component mounts, as the RoutingCat skill shows.
Fix: Read usePathname() after the component mounts.
D43
Warning, shown in init. Several Next.js apps below the folder.
several_apps:Several Next.js apps here: {apps}. Run npx routingcat init in the folder of the app to set up.
Fix: Run npx routingcat init in the app’s own folder.
D44
Warning, shown in init and doctor. Next.js not installed.
next_not_installed:Next.js is not installed here. Run {install}, then npx routingcat init again.
Fix: Run the install command it names, then npx routingcat init again.
D45
Warning, shown in the build log. The Vercel project is bound to another site.
project_bound_elsewhere:routingcat: this Vercel project belongs to the RoutingCat site {bound}, not {site}, so this build registers nothing and visitors get your defaults.
Fix: The build still ships, but registers nothing, so visitors get your defaults. Set site in the project’s config, routingcat.config.ts, a JavaScript app’s routingcat.config.mjs or a template site’s routingcat.config.json, to the site the Vercel project belongs to.
D46
Warning, shown in the build log and doctor. A build run on your own machine; or, for doctor, a production page that such a build’s development values serve, deciding nothing away from that machine.
local_build:routingcat: a build on your own machine registers nothing and serves your defaults.local_development:routingcat: a build on your own machine, with no Vercel or GitHub Actions OIDC token and no ROUTINGCAT_DEPLOY_KEY, registers nothing. Under wrangler dev or vercel dev its pages run in development mode, where ?rc= shows the variants you name and nothing is recorded; deployed, they decide nothing. To deploy a site on Cloudflare from this machine, run the build with ROUTINGCAT_ENV=production.development_served:{url} is served by a build made for development on a person's machine, which decides nothing there: visitors get your defaults and nothing is recorded. Deploy a build made in CI, or, on Cloudflare, one run on that machine with ROUTINGCAT_ENV=production.
Fix: Nothing to fix on your machine: a build there registers nothing and serves your defaults. After routingcat build there, or Astro’s, Nuxt’s or React Router’s build, wrangler dev or vercel dev runs your pages in development mode, where ?rc= shows the variants you name. Deployed, such a build decides nothing: deploy a build made in CI, or, for a site on Cloudflare, one run on your machine with ROUTINGCAT_ENV=production, which registers production under your sign-in once you confirm its plan.
D47
Warning, shown in push. push run by hand, outside a build.
push_outside_build, exit 2:routingcat push runs inside your build, not by hand. To see what a deploy would make live, run routingcat plan.
Fix: push runs in your build. To see what a deploy would make live, run npx routingcat plan.
D48
Warning, shown in plan and push. A wrapper route sets dynamicParams = false.
dynamic_params_false, exit 1:{wrapper} sets dynamicParams = false, so every variant but the default would answer 404. Remove that line.
Fix: Remove it: with it, every variant but the default would answer 404.
D49
Error, shown in status. The control’s share of new visitors differs from its setting, in the form of what decides the page: a server, by the host its newest production deployment registered, or browsers.
control_ratio:{page}: the control got {observed}% of new visitors, not {expected}%. Visitors still get the page, but the measured gain may be biased: check caching and the proxy's matcher on this page.middleware_control_ratio:{page}: the control got {observed}% of new visitors, not {expected}%. Visitors still get the page, but the measured gain may be biased: check caching and the middleware's matcher on this page.worker_control_ratio:{page}: the control got {observed}% of new visitors, not {expected}%. Visitors still get the page, but the measured gain may be biased: check caching in front of the Worker on this page, and that the Worker runs on it first, as run_worker_first, _routes.json or its route says.browser_control_ratio:{page}: the control got {observed}% of new visitors, not {expected}%. Visitors still get the page, but the measured gain may be biased: browsers decide it, so no cache or matcher stands in the way. Run routingcat doctor, which checks what the page loads.
Fix: The measured gain may be biased. Where a server decides the page, check caching on it, and what runs RoutingCat there: the proxy’s matcher, the middleware’s, or for a Worker, run_worker_first, _routes.json or its route. Where browsers decide it, run npx routingcat doctor, which checks what the page loads.
D50
Warning, shown in every command. The credential cannot be stored or renewed: a read-only sandbox; in a Shopify theme’s or a Hydrogen storefront’s folder, the pairing with its store’s site cannot be kept.
sandbox_read_only, exit 3:This sandbox cannot keep a sign-in. Run npx routingcat login in your own terminal, then run this command again.sandbox_cannot_pair, exit 3:This sandbox cannot keep a pairing. Run npx routingcat init in your own terminal, in the theme's or storefront's folder, then run this command again.
Fix: Run npx routingcat login in your own terminal, outside the sandbox, then run the same command again. In a Shopify theme’s or a Hydrogen storefront’s folder, run npx routingcat init there instead, which pairs it.
D51
Warning, shown in init. No project init recognizes in the folder, above it or below it: no Next.js, Nuxt or Astro app, no Hydrogen storefront, no Shopify theme and no site with templates.
no_project:No project init recognizes here: a Next.js, Nuxt or Astro app, a Hydrogen storefront, a Shopify theme, or a site with templates. Run npx routingcat init in your project's folder.
Fix: Run npx routingcat init in your project’s folder: a Next.js, Nuxt or Astro app, a Hydrogen storefront, a Shopify theme, or a site whose templates or pages carry the slot markup.
D52
Warning, shown in init. Installing the routingcat package failed.
install_failed:{command} failed, so init stopped before changing your files. Install the routingcat package yourself, then run npx routingcat init again.
Fix: init stopped before changing your files. Install the package with the command it names, then run npx routingcat init again.
D53
Warning, shown in the build log. A variant’s own file imports a data file it does not declare.
undeclared_data_file:routingcat: {file} imports {data} without declaring it, so editing {data} would change what the variant shows without making a new version. Declare it in the variant's content.
Fix: The build still ships, but editing that data file would change what the variant shows without making a new version. Declare the data in the variant’s content.
D54
Warning, shown in the build log. No config: routingcat.config.ts, or routingcat.config.mjs in a JavaScript app.
no_config:routingcat: no {config}, so this build registers nothing and serves your defaults. Run npx routingcat init.
Fix: The build still ships, but registers nothing and serves your defaults. Run npx routingcat init, which writes the config.
D55
Warning, shown in every command. A failure inside the command.
internal_error:RoutingCat hit an internal error: {detail}. This is not your doing: run the command again, and if it repeats, report this line.
Fix: Not your doing. Run the command again; if it repeats, report the line.
D56
Warning, shown in doctor. The publicKey in the code’s config, routingcat.config.ts, or routingcat.config.mjs in a JavaScript app, is not the site’s public key.
wrong_public_key:{file} names the key {configured}, which is not {site}'s public key, so RoutingCat refuses events from browsers: conversions tracked in the browser are not counted. Run npx routingcat init to correct it.
Fix: RoutingCat refuses events from browsers until the key matches. Run npx routingcat init, which corrects the key, then deploy.
D57
Warning, shown in init, doctor and status. Cloudflare is in front of the site, most of its page loads coming through it, without its visitor location headers.
cloudflare_without_location:Cloudflare is in front of {host} without its visitor location headers, so visitors' local times come from the Cloudflare location they reached, or from their country. In Cloudflare: {zone} → Rules → Settings → Managed Transforms → turn on "Add visitor location headers".cloudflare_in_front:{host} answers through Cloudflare. If its visitor location headers are off, visitors' local times come from the Cloudflare location they reached, or from their country: in Cloudflare, {zone} → Rules → Settings → Managed Transforms → turn on "Add visitor location headers".
Fix: Visitors’ local times, and the time-of-day breakdowns built on them, then come from the Cloudflare location they reached, or from their country. In Cloudflare: the domain → Rules → Settings → Managed Transforms → turn on Add visitor location headers. At init, which cannot see those headers, turn them on if they are off.
D58
Warning, shown in doctor and connect. A connection waiting for its setup to finish: Stripe’s install link not followed yet, no Whop API key to create its webhook with, or a Whop webhook whose first delivery has not yet proven that the account is the seller’s.
connection_pending, exit 3:{provider} is not connected yet: open the install link routingcat connect {command} printed, choose your account, then run routingcat doctor again.whop_key_needed, exit 3:routingcat connect whop needs a Whop API key with {scopes}: set WHOP_API_KEY, or run the command at a terminal to type it. Make the key in Whop's dashboard; it is never written to disk.whop_delivery_awaited, exit 3:Whop is not connected yet: the first delivery of the webhook {webhook} proves the account is yours. Send its test event in Whop's dashboard, in Developer, Webhooks, then run routingcat doctor again.
Fix: For Stripe, open the install link routingcat connect stripe printed and choose your account. For Whop, set WHOP_API_KEY or run routingcat connect whop at a terminal to type the key; it is never written to disk. Once the webhook exists, send its test event in Whop’s dashboard, in Developer, Webhooks: its first delivery binds the account.
D59
Error, shown in doctor and status. A connection disconnected: the provider withdrew access, or its webhook was disabled.
connection_disconnected:{provider} was disconnected from {site} at {time} UTC ({reason}), so {outcomes} since then are not recorded: they count as unobservable, never as zero. Run routingcat connect {command} to reconnect.
Fix: Reconnect with routingcat connect stripe or routingcat connect whop. Until then, the outcomes the connection reported count as unobservable, never as zero.
D60
Error, shown in doctor, status and connect. Deliveries from a connection’s provider carry a signature RoutingCat cannot verify.
signature_failing:Payments from {provider} have arrived with a signature RoutingCat cannot verify since {time} UTC, so they are refused: the webhook's secret changed. Run routingcat connect {command} again.
Fix: The webhook’s secret changed: run routingcat connect whop again, which creates a new webhook and deletes the old one.
D61
Warning, shown in status. A Stripe or Whop connection’s purchases with no visitor id and an account never linked, in the last 7 days.
stripe_purchases_unlinked:{count} Stripe purchases in the last 7 days carry no visitor id, so they cannot be credited to a visit. Put rc_vid in the metadata of the PaymentIntent or subscription your checkout creates (docs.routingcat.com/guides/stripe).whop_purchases_unlinked:{count} Whop purchases in the last 7 days carry no visitor id, so they cannot be credited to a visit. Put rc_vid in the metadata of Whop's embedded checkout, or of the checkout configuration your server creates: a plain plan link carries none (docs.routingcat.com/guides/whop).
Fix: Put rc_vid in the metadata of the PaymentIntent or subscription your Stripe checkout creates; with Whop, in the metadata of its embedded checkout or of the checkout configuration your server creates, since a plain plan link carries none. The documentation’s Stripe and Whop guides show how.
D62
Information, shown in status. The same outcome reported by the site’s own webhook code and by a connection, in the last 7 days.
recipe_and_connector:{event} is reported by your {provider} webhook code and by the {provider} connection; each payment counts once. The code can go.
Fix: Nothing double counts: each payment counts once. Removing the webhook code is your call.
D63
Information, shown in doctor. A connection whose outcomes are all in preview so far.
connection_sandbox_only:{provider} is connected: {count} sandbox {noun} arrived, in preview. Live {plural} will count once they happen.
Fix: Nothing to do: the outcomes of a sandbox or a development store stay in preview, outside evidence, and live ones count once they happen.
D64
Error, shown in connect. Whop refused, or could not be reached, while connect whop created or tested its webhook.
whop_refused, exit 1:Whop refused to {act} ({status}): the API key needs {scopes}. Make one in Whop's dashboard, then run routingcat connect whop again.whop_unreachable, exit 1:Whop could not be reached at {host}, so nothing was connected. Run routingcat connect whop again.
Fix: Make a Whop API key in Whop’s dashboard with developer:manage_webhook, and with --reconcile the read permissions too, then run routingcat connect whop again.
D65
Error, shown in connect. A setup that cannot bind its provider account: the account feeds another site already, the key is another account’s, or the setup expired.
account_on_another_site, exit 1:{provider} account {account} already sends its payments to {other}, and one account feeds one site for now. Remove that connection first, or connect another account.whop_account_held, exit 1:Whop account {account} already sends its payments to another site, and one account feeds one site for now. If the account is yours, prove it with your API key: run {command}. RoutingCat checks the key once with Whop and keeps it only with --reconcile.whop_account_proven_elsewhere, exit 1:Whop account {account} already sends its payments to another site, whose connection its own API key proved, and one account feeds one site for now. Remove that connection first, or connect another account.account_mismatch, exit 1:This Whop key belongs to {account}, but {site}'s Whop connection is {connected}: run routingcat disconnect {connection} first, then connect again.setup_expired, exit 1:This {provider} setup expired or was used already: run routingcat connect {command} again.
Fix: One provider account feeds one site for now: remove its connection on the other site with routingcat disconnect, or connect another account. A Whop account a delivery alone bound to another site moves to yours once your API key proves it: run routingcat connect whop --prove; RoutingCat checks the key once with Whop and keeps it only with --reconcile. An expired setup starts again with routingcat connect.
D66
Warning, shown in plan, push and the build log. Slot markup the scan of a template site cannot read: a key written as a template expression, a variant that does not close within its slot, or a slot in an indentation-based template.
markup_expression, exit 1:{file}:{line}: {attribute} is written as a template expression, {value}, so routingcat cannot read this slot from your templates. Write the key itself: lowercase letters, digits, - and _.markup_unbalanced, exit 1:{file}:{line}: {address} does not close where it should, so routingcat cannot tell where it ends. Close every tag inside the variant that opens it, and in the same branch of a conditional.markup_indented, exit 1:{file} is a {language} template, where routingcat cannot read slot markup. Put the slot in an HTML-syntax partial and include it there.
Fix: Write slot markup the scan can read: the page, slot and variant keys written as themselves, every tag closed inside the variant that opens it and in the same branch of a conditional, and slots in HTML-syntax templates rather than Haml, Slim or Pug.
D67
Warning, shown in plan, push and the build log. Slot markup that breaks its grammar, or one slot written two ways in the templates.
markup_invalid, exit 1:{file}:{line}: {address} {problem}.markup_instances, exit 1:{address} is written differently in {first} and {second}: every copy of a slot carries the same variants, in the same order, with the same content.
Fix: A slot is a container carrying data-rc-page, data-rc-slot and style="display:contents" around its variants, each carrying data-rc-variant: the default shown, every other one hidden with no inline display, every image lazy. Every copy of a slot carries the same variants. npx routingcat push writes the hashes and the default’s style.
D68
Warning, shown in plan, push and the build log. A slot where the browser’s parser moves or splits it: a div inside a paragraph, directly inside a table, a list or a select, inside another slot’s variant, or in the head.
markup_in_paragraph, exit 1:{file}:{line}: {address} is a <{tag}> inside a paragraph, which the browser closes before it, so the slot falls apart. Inside a paragraph, the container and its variants are span elements.markup_moved, exit 1:{file}:{line}: {address} sits directly inside <{parent}>, where the browser moves it out. Put the container inside the cell or the item, or around the whole list.markup_nested, exit 1:{file}:{line}: {address} sits inside {outer}, a variant of another slot, and slots do not nest. Make it a slot beside the other one.markup_in_head, exit 1:{file}:{line}: {address} is inside <head>, which cannot be a slot. Put the slot in the body.
Fix: Keep each slot where the browser leaves it in place: span elements for a slot inside a paragraph, a container inside a table cell or a list item rather than directly in the table or the list, no slot inside another slot’s variant, and none in the head.
D69
Warning, shown in plan, push and the build log. A variant holding what stays active while it is hidden: a script that runs, structured data, a stylesheet, an id given twice, more than one h1 or one beside the page’s, or a form.
variant_script, exit 1:{file}:{line}: {address} holds a script that runs, or structured data that search engines read, even while the variant is hidden. Move it out of the variant.variant_stylesheet, exit 1:{file}:{line}: {address} holds a stylesheet, which styles the whole page even while the variant is hidden. Move it out of the variant.variant_duplicate_id, exit 1:{file}:{line}: {address} gives the id {id}, which {other} gives too, and a hidden variant stays in the page. Give each element its own id.variant_headings, exit 1:{file}:{line}: {address} holds {count} h1 headings; a variant holds one at most.variant_heading_beside, exit 1:{file}:{line}: {address} holds an h1, and the page has another outside the slot. Only a slot that owns the page's heading holds an h1.variant_form:{file}:{line}: {address} holds a form, which still submits while the variant is hidden. Make sure it works once shown and does nothing until then, or keep it in the default.
Fix: Hidden variants stay in the page: keep scripts, structured data and stylesheets out of them, give each id once, hold one h1 at most and only in a slot that owns the page’s heading, and keep forms to variants where they work once shown.
D70
Warning, shown in plan, push and the build log. The slot markup and routingcat.config.json disagree: a page the markup names and the config does not declare, or a slot or variant the config names and no template carries.
markup_page_undeclared, exit 1:{file}:{line}: {address} belongs to the page {page}, which routingcat.config.json does not declare. Add the page under pages, with its routes.config_names_nothing, exit 1:routingcat.config.json: {field} names {address}, which no template carries. Correct the address, or remove the entry.
Fix: Declare each page of the markup under pages in routingcat.config.json, with its routes, and name slots and variants there as the markup names them.
D71
Warning, shown in push, the build log and doctor. Templates whose stamps routingcat push would change, a stale or missing data-rc-hash or a default without its style, or a head partial out of date: in push –check, and in the build of a site whose middleware decides.
stamps_stale, exit 1:Your templates lack {count} of the edits routingcat push makes, so their slots would report other versions than this deploy registers. Run routingcat push, then commit what it changes.partial_stale, exit 1:{file} is not the head partial these templates and routingcat {version} make. Run routingcat push, then commit it.
Fix: Run npx routingcat push in your repository, then commit what it changes; routingcat push --check in CI fails until you do.
D72
Information, shown in push. routingcat push run where it registers nothing: a script site’s push with no credential to register with, neither CI’s GitHub token or deploy key nor, with --env production, the person’s, or the push of a site whose build registers.
push_no_credential:routingcat push registered nothing: it registers in CI, with GitHub's token once routingcat link github links this site to its repository, or with the site's deploy key in ROUTINGCAT_DEPLOY_KEY, and neither is here. From this machine, routingcat push --env production registers production once you confirm the plan it shows. Commit what it changed.push_build_registers:Your build registers these templates on every deploy, through routingcat build. Commit what routingcat push changed; routingcat plan shows what a deploy would make live.
Fix: Commit what routingcat push changed. A script site registers production from a person’s machine with routingcat push --env production, which shows the plan and pushes it once the person confirms it; in CI, with GitHub’s OIDC token once routingcat link github links the site to its repository, or with its deploy key in ROUTINGCAT_DEPLOY_KEY, from routingcat keys deploy --branch <production branch>. A site whose middleware decides registers in its build, through routingcat build.
D73
Warning, shown in push and doctor. Slot markup in built or served HTML that differs from what the templates declare: routingcat push –built, and doctor on each page’s representative URL, as when a build drops attributes or renders other variants.
built_differs, exit 1:{file}:{line}: {address} {problem}. Build from the templates routingcat push stamped, keeping the slot markup as written.served_differs:{url}: {address} {problem}. Deploy the templates routingcat push stamped, keeping the slot markup as written.
Fix: Build and deploy from the templates routingcat push stamped, and keep the slot markup as written: a minifier or a template that drops data-rc-* attributes or hidden breaks the slots.
D74
Warning, shown in init. init cannot tell where the site deploys: the folder holds no host’s configuration, or several; for a site its own server renders, whether Vercel, a Cloudflare Worker in front of its server, or neither serves it.
host_unknown, exit 2:init cannot tell where this {stack} site deploys: {found}. Run npx routingcat init again with --host and one of {choices}.host_unknown_server, exit 2:init cannot tell where this {stack} site is served: {found}. Run npx routingcat init again with --host vercel where Vercel serves it, --host cloudflare-workers for a Cloudflare Worker in front of your server, or --host none for neither: the script integration, which decides in the page.
Fix: Run npx routingcat init --host with the host the site deploys to: vercel, cloudflare-workers or cloudflare-pages, or none for a host that runs nothing of RoutingCat’s, where the script integration decides in the page. A site your own server renders takes vercel, cloudflare-workers for a Cloudflare Worker in front of your server, or none.
D75
Warning, shown in init. Several sites below the folder, not all Next.js apps.
several_sites:Several sites here: {sites}. Run npx routingcat init in the folder of the site to set up.
Fix: Run npx routingcat init in the site’s own folder.
D76
Warning, shown in init and doctor. Nuxt not installed.
nuxt_not_installed:Nuxt is not installed here. Run {install}, then npx routingcat init again.
Fix: Run the install command it names, then npx routingcat init again.
D77
Warning, shown in init and doctor. Nuxt below 4.6, the first whose Kit takes the inputs routingcat/nuxt passes for each Nitro, but Nuxt 2 built static, which init sets up as a site with templates.
nuxt_unsupported:This app has Nuxt {version}, and RoutingCat needs Nuxt 4.6 or later. Upgrading is your call: npx nuxt upgrade --dedupe.nuxt2_server:This app has Nuxt {version}, built by a server, and RoutingCat sets Nuxt 2 up only for static builds, which nuxt generate makes. Set target: 'static' in nuxt.config and build with nuxt generate, or move to Nuxt 4 with Nuxt's migration guide, then run npx routingcat init again.
Fix: Upgrading Nuxt is your call: npx nuxt upgrade --dedupe. RoutingCat supports the Nuxt majors upstream maintains, from Nuxt 4.6. On Nuxt 2, which that command does not upgrade, RoutingCat sets up static builds: set target: 'static' in nuxt.config and build with nuxt generate.
D79
Warning, shown in init. Wrangler is not signed in, or reaches several Cloudflare accounts while the Wrangler configuration names none.
wrangler_signed_out, exit 3:Wrangler is not signed in, so init cannot name the Cloudflare account your site deploys from. Run npx wrangler login, then npx routingcat init again.cloudflare_accounts:Wrangler reaches several Cloudflare accounts: {accounts}. Set account_id in {file} to the one this site deploys from, then run npx routingcat init again.
Fix: Run npx wrangler login, or set account_id in the Wrangler configuration to the account the site deploys from, then npx routingcat init again. Signing in to Cloudflare needs you, not your agent.
D80
Warning, shown in init and doctor. Workers Cache turned on for the Worker RoutingCat runs in, under which Cloudflare bills every request to that Worker, its static files’ included, while it caches none of RoutingCat’s pages, each of which sets the visitor cookie.
workers_cache:{file} turns on Workers Cache for the Worker RoutingCat runs in, so Cloudflare bills every request to that Worker, your static files' included, while Workers Cache keeps none of your pages, since each one sets RoutingCat's visitor cookie. Remove its cache setting.
Fix: Remove cache from the Wrangler configuration of the Worker RoutingCat runs in: with Workers Cache on, Cloudflare bills every request to that Worker, its static files’ included, and caches none of its pages, each of which sets RoutingCat’s visitor cookie. A cached entrypoint behind RoutingCat’s comes later.
D81
Warning, shown in init. A static site whose pages sit at the project’s root, which its host would publish with the build’s credential.
pages_into_public:This site's pages sit at the project's root, which {host} would publish whole, .routingcat/ included, where the build writes RoutingCat's credential. Move them into public/, where init finds them by public/index.html, then run npx routingcat init again, or run it with --host none for the script integration.
Fix: Move the site’s pages into public/, and publish that folder: init recognizes a site of HTML pages by public/index.html, or by an index.html at the project’s root, and takes no other folder. Or run npx routingcat init --host none, whose pages decide in the browser.
D82
Warning, shown in doctor. The host’s middleware did not run on a page: Vercel’s root middleware, a Worker, Pages’ or Oxygen’s.
middleware_not_running:{url} answered without RoutingCat's visitor cookie, rc_vid, so the middleware did not run on {path}: visitors there get your defaults, and their visits are not recorded. middleware.ts must export middleware(…) from routingcat/vercel and keep RoutingCat's matcher entries.worker_not_running:{url} answered without RoutingCat's visitor cookie, rc_vid, so the Worker did not run on {path}: visitors there get your defaults, and their visits are not recorded. The Worker's main must export worker(…) from routingcat/cloudflare, and run_worker_first must keep RoutingCat's patterns.pages_middleware_not_running:{url} answered without RoutingCat's visitor cookie, rc_vid, so the Pages middleware did not run on {path}: visitors there get your defaults, and their visits are not recorded. functions/_middleware.ts must export onRequest = pages(…) from routingcat/cloudflare.upstream_worker_not_running:{url} answered without RoutingCat's visitor cookie, rc_vid, so the Worker in front of your server did not run on {path}: visitors there get your defaults, and their visits are not recorded. Its main must export worker(…) from routingcat/cloudflare in upstream mode, and its route must cover your pages.html_worker_not_running:{url} answered without RoutingCat's visitor cookie, rc_vid, so the Worker did not run on {path}: visitors there get your defaults, and their visits are not recorded. Its main must export worker(…) from routingcat/cloudflare; in front of your site's files, run_worker_first must keep RoutingCat's patterns, and in front of your server, its route must cover your pages.pages_worker_not_wrapped:{url} answered without RoutingCat's visitor cookie, rc_vid, so RoutingCat did not run on {path} in the Worker your Pages build wrote: visitors there get your defaults, and their visits are not recorded. Keep routingcat/nuxt in nuxt.config's modules, whose build wraps that Worker, and build with Nitro's cloudflare_pages preset.oxygen_not_running:{url} answered without RoutingCat's visitor cookie, rc_vid, so RoutingCat did not run on {path} in your Oxygen Worker: visitors there get your defaults, and their visits are not recorded. server.ts must export oxygen(…) from routingcat/fetch around React Router's handler.
Fix: The host’s entry runs RoutingCat on every page, as npx routingcat init writes it: Vercel’s root middleware.ts exporting middleware(…) from routingcat/vercel, a Worker exporting worker(…) from routingcat/cloudflare with its run_worker_first, Pages’ functions/_middleware.ts, a Nuxt build that wraps the Worker Pages runs, or Hydrogen’s server.ts exporting oxygen(…) from routingcat/fetch. If a firewall challenged the request, doctor reads the live activity instead.
D83
Error, shown in doctor and status. No deployment has registered since a build registered a change, on a host whose middleware, Worker or server registers it, or on a script site, whose push registers it.
middleware_unregistered:Your deployment from {ago} ago has not registered, so visitors may not be getting its changes yet. A deployment registers on its first request: open {url} or run routingcat doctor. If it still does not, check that middleware.ts exports middleware(…) from routingcat/vercel.worker_unregistered:Your deployment from {ago} ago has not registered, so visitors may not be getting its changes yet. A deployment registers on its first request: open {url} or run routingcat doctor. If it still does not, check that the Worker's main exports worker(…) from routingcat/cloudflare.pages_unregistered:Your deployment from {ago} ago has not registered, so visitors may not be getting its changes yet. A deployment registers on its first request: open {url} or run routingcat doctor. If it still does not, check that functions/_middleware.ts exports onRequest = pages(…) from routingcat/cloudflare.pages_worker_unregistered:Your deployment from {ago} ago has not registered, so visitors may not be getting its changes yet. A deployment registers on its first request: open {url} or run routingcat doctor. If it still does not, check that nuxt.config's modules keep routingcat/nuxt, whose build wraps the Worker Pages runs.server_unregistered:Your deployment from {ago} ago has not registered, so visitors may not be getting its changes yet. A deployment registers on its first request: open {url} or run routingcat doctor.script_unregistered:Your deployment from {ago} ago has not registered, so visitors may not be getting its changes yet. routingcat push registers it last, after its changes: run it again in CI on the same templates, which registers that deployment or says why it cannot.oxygen_unregistered:Your deployment from {ago} ago has not registered, so visitors may not be getting its changes yet. A deployment registers on its first request: open {url} or run routingcat doctor. If it still does not, check that server.ts exports oxygen(…) from routingcat/fetch.
Fix: A deployment registers on its first request: open the site, or run npx routingcat doctor. If it still does not register, check the host’s entry, as npx routingcat init writes it. A script site’s registers at the end of npx routingcat push: run it again in CI on the same templates.
D84
Warning, shown in doctor. Browser events skip the site’s /_rc path, on a host whose middleware or Worker answers it.
vercel_rc_missing:Browser events go to {host} directly, not through your site's /_rc path, so ad blockers can stop them: for visitors who use one, conversions tracked in the browser are not counted. Keep '/_rc/:path*' in middleware.ts's matcher.upstream_rc_missing:Browser events go to {host} directly, not through your site's /_rc path, so ad blockers can stop them: for visitors who use one, conversions tracked in the browser are not counted. Keep the Worker's route on every path of your site, /_rc/* included.cloudflare_rc_missing:Browser events go to {host} directly, not through your site's /_rc path, so ad blockers can stop them: for visitors who use one, conversions tracked in the browser are not counted. Keep /* among the paths the Worker runs first on, in run_worker_first or _routes.json.html_worker_rc_missing:Browser events go to {host} directly, not through your site's /_rc path, so ad blockers can stop them: for visitors who use one, conversions tracked in the browser are not counted. Keep /* among the paths the Worker runs first on, in run_worker_first, or, for a Worker in front of your server, its route on every path of your site, /_rc/* included.oxygen_rc_missing:Browser events go to {host} directly, not through your site's /_rc path, so ad blockers can stop them: for visitors who use one, conversions tracked in the browser are not counted. Keep oxygen(…) from routingcat/fetch around server.ts's export, which answers /_rc before React Router.
Fix: Keep RoutingCat’s entry for /_rc where the host sends requests to its middleware, as npx routingcat init writes it: '/_rc/:path*' in Vercel’s middleware.ts matcher, /* in a Worker’s run_worker_first or in Pages’ _routes.json, oxygen(…) around Hydrogen’s server.ts export.
D85
Warning, shown in doctor. Vercel runs the root middleware on another runtime than Node.js, which RoutingCat’s middleware needs.
middleware_not_node:{deployment} reports no Node.js version, so Vercel runs middleware.ts on another runtime than Node.js, which RoutingCat's middleware needs: visitors may get your defaults. Keep runtime: 'nodejs' in middleware.ts's config, then redeploy.
Fix: Declare runtime: 'nodejs' in middleware.ts’s config, as npx routingcat init writes it, then redeploy.
D86
Warning, shown in doctor. A Worker’s deployment registered without its version, which the version metadata binding gives, or an Oxygen deployment without Oxygen’s deployment id.
worker_version_missing:{deployment} registered without its Worker's version, so each of its isolates registers on its own. Add the version metadata binding, CF_VERSION_METADATA, to {file}, as npx routingcat init writes it, then redeploy.oxygen_deployment_missing:{deployment} registered without Oxygen's deployment id, so each of its isolates registers on its own: Oxygen sends oxygen-buyer-deployment-id with every request it serves, and this deployment's requests carried none. Deploy the storefront to Oxygen, with shopify hydrogen deploy.
Fix: Add the version metadata binding, "version_metadata": { "binding": "CF_VERSION_METADATA" }, to the Wrangler configuration, as npx routingcat init writes it, then redeploy. On Oxygen, which names each deployment in every request, deploy with shopify hydrogen deploy.
D87
Information, shown in init. A stack whose host runs nothing of RoutingCat’s before the HTML: the script integration.
script_integration:{stack} renders this site's pages with nothing of RoutingCat's running before the HTML, so RoutingCat decides in the page: the script integration. On a host whose middleware runs RoutingCat, such as Vercel or Cloudflare, the same templates would take server decisions: a visitor id the server sets for 400 days, secret seeds, no wait on a first view, and geography from the first view.
Fix: Nothing to fix. To move the site to a host whose middleware runs RoutingCat, run npx routingcat init --host vercel, or --host cloudflare-workers for a Worker in front of your server: it moves the site and sets up the server’s decisions, keeping its templates. Without --host, init keeps the integration the config names.
D88
Warning, shown in init. A script site, a site its own server renders behind a Worker on Cloudflare in upstream mode, or a Nuxt, Astro or static site on Cloudflare, whose production address init finds nowhere: not in its stack’s configuration, nor, on Cloudflare, in its Wrangler routes.
origin_needed, exit 2:init needs this site's production address, which {stack}'s configuration does not give. Run npx routingcat init again with --origin and the address, as --origin https://www.example.com.origin_needed_worker, exit 2:init needs this site's production address, for the route of the Worker in front of your server, and neither {stack}'s configuration nor a Wrangler route gives it. Run npx routingcat init again with --origin and the address, as --origin https://www.example.com.origin_needed_cloudflare, exit 2:init needs this site's production address, for doctor's checks and preview links, and neither {stack}'s configuration nor a Wrangler route gives it. Run npx routingcat init again with --origin and the address, as --origin https://www.example.com.
Fix: Run npx routingcat init --origin with the site’s production address, as https://www.example.com. A script site’s head partial lists its host, where the page’s decisions count as production; the Worker in front of a server runs on its route, and the config lists it as production; a Nuxt or Astro site’s config() names it as origin, and a static site’s routingcat.config.json lists it as production, the address doctor checks and preview links open.
D89
Warning, shown in doctor. A page whose head partial, or the selection handed to it, does not reach the browser as pushed: missing, out of place, unreadable, naming templates no push registered or whose push’s routing data for browsers RoutingCat has not published yet, carrying a core turned off, or a routed page’s answer without its rc entry; or a page of a site its own server renders, behind a Worker in upstream mode, whose slot markup carries a hash the Worker’s deployment did not register.
partial_missing:{url} carries no RoutingCat head partial in its <head>, so RoutingCat never decides there: visitors get your defaults, and their visits are not recorded. Include {partial} first in the <head> of the layout that renders {path}.snippet_missing:{url} carries no RoutingCat head snippet in its <head>, so visitors routed there see your defaults. Include {partial} first in the <head> of the layout that renders {path}.partial_not_first:{url}: RoutingCat's head partial comes after {before} in <head>, so its first decision waits for it. Include the partial first in <head>, after the charset and viewport tags.partial_unreadable:{url}: the head manifest in RoutingCat's head partial cannot be read ({problem}), so the page shows your defaults. Run routingcat push, then deploy what it changed.partial_unregistered:{url}: RoutingCat's head partial names the manifest {manifest}, which no push registered, so the page shows your defaults. Run routingcat push in CI after your deploy, as npx routingcat init printed it.partial_unlisted:{url}: RoutingCat's head partial names the manifest {manifest}, which a push registered, but RoutingCat's bundle for {page}, compiled since, does not list it, so the page shows your defaults and records no decision. Run routingcat push in CI again, which compiles the bundles that list it.markup_unregistered:{url}: {address} carries the hash {hash} for {variant}, which the Worker in front of your server did not register, so the slot shows your default and RoutingCat records no decision for it. Deploy the Worker with your server's templates: its build runs routingcat build, which registers them.core_disabled:{url} runs RoutingCat's core {core}, which RoutingCat turned off for a fault, so the page shows your defaults. Upgrade routingcat, run routingcat push, then deploy what it changed.entry_missing:{url} is a routed page, but its answer carries no rc entry in Server-Timing, so its visitors see your defaults. Keep Server-Timing on the site's pages: a header rule or a proxy in front removes it.decision_entry_missing:{url} is a routed page, but its answer carries no rc entry in Server-Timing, so the browser cannot tell which decision its visitors saw: their visits from links on your site are not counted. Keep Server-Timing on the site's pages: a header rule or a proxy in front removes it.nuxt_snippet_missing:{url} carries no RoutingCat head snippet in its <head>, so visitors routed there see your defaults. Keep routingcat/nuxt in nuxt.config's modules, which writes it into every page's <head>.nuxt2_snippet_missing:{url} carries no RoutingCat head snippet in its <head>, so visitors routed there see your defaults. Keep RoutingCat's script entries in {config}'s head, the snippet's hid named in __dangerouslyDisableSanitizersByTagID, as npx routingcat init writes them.
Fix: Include the head partial routingcat push writes first in each layout’s <head>, after the charset and viewport tags; run routingcat push --check in CI before each deploy and routingcat push right after it, as npx routingcat init printed it, since a page whose templates no push registered shows your defaults and records no decision, until RoutingCat publishes the routing data of its push, about two minutes after it; run routingcat push after each upgrade and deploy what it changed; keep Server-Timing on the site’s pages. Behind a Worker in front of your server, deploy the Worker with each change of the server’s templates, since a slot whose markup the Worker’s deployment did not register shows its default.
D90
Information, shown in doctor. A page whose core or post part is older than the one this version of routingcat pins.
runtime_outdated:{url} runs RoutingCat's {part} {version}, older than {latest}, which this routingcat pins. Run routingcat push, then deploy what it changed, when you choose.
Fix: Nothing to fix now: the page keeps the versions it was deployed with. Run routingcat push and deploy what it changed when you choose to move to the newer ones.
D91
Warning, shown in doctor. The post part a script site’s head partial names does not load, or not as pinned.
post_part_failed:{url}: RoutingCat's post part, {script}, does not load ({problem}), so the page sends no render beacon and refreshes no bundle. Let pages load it from {host}, then run routingcat doctor again.
Fix: The post part loads from RoutingCat’s CDN, pinned by version and integrity: let the page load it, and nothing alter it on the way.
D92
Warning, shown in doctor. A page’s Content Security Policy blocks what RoutingCat runs in it: its inline scripts, its hosts, its style rules or the slot markup’s style.
csp_inline:{url}'s Content Security Policy runs no inline script but by nonce or hash, and RoutingCat's {script} carries neither, so {effect}. Add {source} to script-src, or give its tag the page's nonce.csp_partial_hash:{url}'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 {partial} the page's nonce in your template, which routingcat push keeps, or add {source} to script-src, the core's hash, which an upgrade of routingcat can change.csp_inline_rewritten:{url}'s Content Security Policy runs no inline script but by nonce or hash, and RoutingCat's {script} carries neither, so {effect}. Your site's build rewrites that script, as Hugo's does, so no hash RoutingCat publishes matches it: give its tag the page's nonce, or add {source}, its hash as the page serves it, to script-src, again whenever your build changes it.csp_host:{url}'s Content Security Policy does not allow {origin} in {directive}, so {effect}. Add {origin} to {directive}.csp_style:{url}'s Content Security Policy lets inline styles apply only by hash, so RoutingCat's style rules cannot show a selection: visitors routed there see your defaults. Allow inline styles by nonce, which RoutingCat copies from its script, or with 'unsafe-inline'.csp_style_attr:{url}'s Content Security Policy refuses the slot markup's style="{style}", so slots render as boxes. Add 'unsafe-hashes' '{hash}' to style-src-attr.
Fix: Let the page’s Content Security Policy allow RoutingCat’s inline scripts by nonce or hash, https://cdn.routingcat.com in script-src and connect-src, https://ingest.routingcat.com in connect-src, inline styles by nonce, and each style the slot markup carries in style-src-attr, with 'unsafe-hashes' and the hash the message names: RoutingCat writes display:contents, and markup that writes it otherwise, as display: contents;, needs that value’s own hash. Where your build rewrites those scripts, as Hugo’s does, allow them by nonce: their hash changes with your build. On a script site, your template gives the head partial’s script tags the page’s nonce, which routingcat push keeps, or the policy lists the core’s hash, which an upgrade of routingcat can change.
D93
Warning, shown in doctor. RoutingCat’s edge does not accept a site’s records from its production origin; on a site bound to a Shopify store, from the store’s own domain, which the app adds to the site’s domains at each sync.
edge_refuses_origin:{edge} does not accept records from {origin}, so visits there are not recorded. Add the domain with npx routingcat domains add {domain}.edge_refuses_store_domain:{edge} does not accept records from {origin} yet. RoutingCat takes your store's domains from Shopify at each sync of its app, so the edge accepts {domain} after the next one, within the hour: there is nothing to add.
Fix: edge_refuses_origin: add the site’s domain with npx routingcat domains add: the edge accepts records from the site’s domains alone. edge_refuses_store_domain: nothing to add: RoutingCat takes a Shopify store’s domains from the store at each sync of its app, every hour, and the edge accepts them from then on; meanwhile a theme’s pages send their records through Shopify’s app proxy, without the visitor’s network location.
D94
Warning, shown in init and doctor. The public_key in routingcat.config.json is not the site’s public key.
config_key_wrong:{file} names the key {configured}, which is not {site}'s public key, so RoutingCat refuses events from browsers: conversions tracked in the browser are not counted. Run npx routingcat init to correct it.
Fix: RoutingCat refuses events from browsers until the key matches. Run npx routingcat init, which corrects the key, then routingcat push, and deploy.
D95
Warning, shown in push and RoutingCat’s answers. A competition among a Shopify theme’s own sections that their rules exclude: sections the template does not hold, a key the selection cannot find alone, copies that do not follow their original, a template past its limits, a section whose scripts, weight, video, preload or app blocks cannot compete, or a first section the theme styles by its position.
section_template, exit 1:{file} is not a JSON template of this theme: sections compete in a template, never in a section group or a vintage theme.section_missing, exit 1:{template}: {key} is not a section of the template. Choose sections it holds, as the theme editor lists them.section_members, exit 1:{template}: a test is the original section and one or two copies of it; {count} sections were chosen.section_key, exit 1:{template}: the section key {key} {problem}, so RoutingCat cannot find that section alone on the page. Copy the section with the theme editor's Duplicate, which gives the copy a key of its own.section_key_shared, exit 1:{template}: {key} is also a section key of {other}, whose section a quick add can bring into the page. Copy the section with the theme editor's Duplicate, which gives the copy a key of its own.section_hidden_original, exit 1:{template}: the original section, {key}, is hidden in the theme editor, so no visitor would see it. Show it, save, then start the test.section_order, exit 1:{template}: {key} comes before {original}, the section it competes with. Move the copy below its original in the theme editor.section_running, exit 1:{template}: {key} already competes in another test. End that test first.section_ended, exit 1:{template}: {key} belongs to a test that ended, whose copies the theme still holds. Delete them in the theme editor: once RoutingCat finds the kept section alone, it can compete again.section_type, exit 1:{template}: {key} is a {type} section, which cannot compete: {reason}.section_template_full, exit 1:{template} would hold {count} sections; a template holds at most 25, copies included.section_copies, exit 1:{template}: {count} copies would compete in the template; at most {limit} in a template.section_copies_early, exit 1:{template}: {count} copies would compete among its first three sections; at most one, so that one image at most loads beside the shown one.section_first, exit 1:{template}: {key} is the template's first section, and {file} styles the first section by its position ({rule}), so a copy shown in its place would look different. Test the first section's content through RoutingCat's hero block instead.
Fix: Compete the theme’s presentational sections, as the theme editor’s Duplicate copies them: the original first, one or two copies below it, at most three copies in a template and one among its first three sections. Test inside a product’s main section, or an image in the first section, through RoutingCat’s blocks.
D96
Warning, shown in push and RoutingCat’s answers. A competition among a Shopify theme’s sections whose rendered page breaks the limits on what hidden copies may cost, so that its arms would load differently or the page would grow heavy: other images among the first three sections, hidden elements or bytes past their limits, video that plays by itself, or structured data in a competing section.
page_images_differ, exit 1:{template}: {key} shows other images than {original} among the page's first three sections, so its arm would load its image later. Keep the original's images in the copy.page_hidden_elements, exit 1:{template}: the competing sections would hide {count} elements of the page's {total}; at most {limit}, and 30% of the page's.page_hidden_bytes, exit 1:{template}: the competing sections would hide {size} of compressed HTML; at most {limit}.page_video, exit 1:{template}: {key} plays video by itself, which would download while the section is hidden.page_structured_data, exit 1:{template}: {key} holds structured data (JSON-LD), which its copies would repeat on the page.
Fix: Keep a copy among the page’s first three sections on its original’s images, changing its text, buttons, colors and layout only, and test images through RoutingCat’s hero block; keep competing sections light, without video that plays by itself or structured data.
D97
Warning, shown in push and RoutingCat’s answers. A competition among a Shopify theme’s sections whose copies move other sections out of the page’s first three, whose images then load later for every visitor, or whose rendered page RoutingCat could not read to check it.
page_indexes_shift:{template}: its copies move {sections} out of the page's first three sections, whose images then load later for every visitor while the test runs.page_unchecked:{template}: RoutingCat could not read the page to check the test's sections ({reason}). It checks them again at the theme's next change.
Fix: Place copies further down the template, or accept that the sections they move load their images later while the test runs. A page RoutingCat could not read is checked again at the theme’s next change; a password-protected store’s pages can be read once its password is removed.
D98
Error, shown in status. The decisions browsers made in the last 7 days that failed RoutingCat’s replay exceed 1% of the site’s browser decisions, or fall in one arm more than its share of them beyond noise.
quarantine_share:{quarantined} of the {decisions} decisions browsers made on your pages in the last 7 days, {share}%, failed RoutingCat's replay, so they are left out of every result: {reasons}. Run routingcat doctor, which checks what your pages run.quarantine_by_arm:The decisions browsers made on your pages in the last 7 days that failed RoutingCat's replay fall unevenly across the arms ({arms}), so the measured gain may be biased: {reasons}. Run routingcat doctor, which checks what your pages run.
Fix: RoutingCat replays each decision a browser makes from what it recorded, and leaves one that fails out of every result, with its reason. For unregistered_deployment, the pages named templates no push had registered, under a core that decided anyway: run routingcat push --check in CI before each deploy and routingcat push right after it, as npx routingcat init printed it, and upgrade routingcat, whose core shows such a page’s defaults and records no decision until RoutingCat publishes the routing data of its push, about two minutes after it. The other reasons are RoutingCat’s to fix, or decisions forged in a browser: RoutingCat replays them again when its replay changes, and those that pass then count.
D99
Warning, shown in init and doctor. Astro not installed.
astro_not_installed:Astro is not installed here. Run {install}, then npx routingcat init again.
Fix: Run the install command it names, then npx routingcat init again.
D100
Warning, shown in init and doctor. Astro below 7.3.1: 7.3 brought the custom entrypoint RoutingCat’s Worker wraps on Cloudflare, and 7.3.0’s builds fail on every site, which 7.3.1 fixed.
astro_unsupported:This app has Astro {version}, and RoutingCat needs Astro 7.3.1 or later. Upgrading is your call: npx @astrojs/upgrade.
Fix: Upgrading Astro is your call: npx @astrojs/upgrade. RoutingCat’s integration needs Astro 7.3.1 or later.
D101
Warning, shown in init and doctor. An Astro site on Cloudflare Workers without Astro’s Cloudflare adapter, which builds the custom entrypoint RoutingCat’s Worker wraps.
astro_no_cloudflare_adapter:This Astro site's config has no Cloudflare adapter, which builds the Worker RoutingCat runs in on Cloudflare Workers. Run npx astro add cloudflare, then npx routingcat init again.
Fix: Add Astro’s Cloudflare adapter, npx astro add cloudflare, then run npx routingcat init again.
D102
Information, shown in init. A site its own server renders, set up for the script integration, whose config declares no server helpers.
helpers_offered:Your {stack} server can set RoutingCat's visitor cookie, which Safari then keeps 400 days instead of 7, and the fetch-site cookie, which tells a visit typed or bookmarked from one that followed a link. If you want it to, run npx routingcat init --helpers, which adds the helpers that set them.
Fix: Run npx routingcat init --helpers: it writes the helpers in the stack’s language, registers them where one line of one file shows where, and declares them in routingcat.config.json. They run on the pages your server renders, never on pages a cache serves.
D103
Warning, shown in init and doctor. Hydrogen’s React Router not installed.
hydrogen_not_installed:Hydrogen is not installed here. Run {install}, then npx routingcat init again.
Fix: Run the install command it names, then npx routingcat init again.
D104
Warning, shown in init and doctor. A Hydrogen storefront on React Router below 7.14, the first whose build runs on Vite 8, which RoutingCat’s Vite plugin needs, or on Remix, without the middleware RoutingCat hands each page’s decision to.
react_router_unsupported:This storefront has React Router {version}, and RoutingCat needs React Router 7.14 or later, whose middleware it hands each page's decision to and whose build runs on Vite 8. Upgrading is your call: npx shopify hydrogen upgrade.hydrogen_on_remix:This storefront runs Hydrogen on Remix, and RoutingCat needs Hydrogen on React Router 7.14 or later, whose middleware it hands each page's decision to and whose build runs on Vite 8. Upgrading is your call: npx shopify hydrogen upgrade.
Fix: Upgrading Hydrogen is your call: npx shopify hydrogen upgrade, to a version on React Router 7.14 or later.
D105
Warning, shown in doctor. A page of a script site whose head partial declares its server helpers answered a navigation without the cookies they set, or with a fetch-site cookie for another address: the helpers not registered, a shared cache answering without running them, or a rewrite in front of the server.
helpers_not_running:{url} answered without {cookies}, which the server helpers your head partial declares set on every page they run on: on its views, RoutingCat knows only what the browser can tell, a visitor id Safari keeps 7 days and no fetch site. Register the helpers as npx routingcat init --helpers printed.helpers_cached:{url} came from a cache ({evidence}), which answered without {cookies}: your server helpers run only on pages your server renders, so its cached views know only what the browser can tell. Let pages through the cache, or leave the helpers off in routingcat.config.json and run routingcat push.helpers_fetch_site_wrong:{url} set rc_fs for another address than its own, so the core refuses it and the visit's fetch site stays unknown. The helper names the page by the request's path and query, which a rewrite in front of your server must leave as the browser sent them.
Fix: Register the helpers as npx routingcat init --helpers printed, so that every page your server renders runs them. A page a shared cache answers runs no helper: let pages through the cache, or leave the helpers off in routingcat.config.json and run routingcat push. A rewrite in front of your server must leave the path and query as the browser sent them, which the fetch-site cookie names its page by.
D106
Warning, shown in init, push, plan, doctor and docs. A script site’s push, plan, doctor, docs, or init where the site pins a version already, each run as the routingcat version routingcat.config.json pins, which its CI runs, through npx --yes routingcat@<pinned>, which cannot fetch that version, npm out of reach or without that version, or runs another for it: each version writes its own head partial, which the other’s push --check refuses (D71).
pinned_version_unavailable, exit 4:This site pins routingcat {pinned} in routingcat.config.json, which its CI runs, and npx could not fetch it here, so nothing ran: this is routingcat {version}, whose head partial your CI would refuse. Check the network and the registry npx uses, then run the same command again, or move to {version}: set "routingcat": "{version}" there and in your CI's steps, then run npx routingcat push.pinned_version_differs, exit 1:This site pins routingcat {pinned} in routingcat.config.json, which its CI runs, and npx ran routingcat {version} for it, whose head partial your CI would refuse, so nothing ran. Check the registry npx uses, then run the same command again, or move to {version}: set "routingcat": "{version}" there and in your CI's steps, then run npx routingcat push.pinned_version_missing, exit 1:This site pins routingcat {pinned} in routingcat.config.json, which its CI runs, and npm has no such version, so nothing ran. The nearest versions npm has: {nearest}. Set "routingcat" to one of them there and in your CI's steps, then run the same command again.
Fix: Commands run the version routingcat.config.json pins themselves, through npx, and stop only where npx cannot fetch that version, or runs another for it. A version npm doesn’t have is the pin’s to change, to one of the versions the message names; otherwise check the network, and the address npm config get registry prints, then run the same command again. To move to another version, set routingcat to it in routingcat.config.json and in the CI’s steps, then run npx routingcat push and commit what it changes.
D107
Warning, shown in init and doctor. A Nuxt app on Cloudflare whose Nitro preset builds no Worker RoutingCat’s wraps there: the cloudflare-pages-static preset, whose build writes the pages alone, so nothing of RoutingCat’s runs before them, or any preset but the host’s, cloudflare_module on Workers and cloudflare_pages on Pages, named in nuxt.config, the environment or the build script.
nuxt_static_preset:nuxt.config sets Nitro's {preset} preset, whose build writes your pages and no Worker, so nothing of RoutingCat's would run before them. Set nitro.preset to cloudflare_pages, or cloudflare_module for Workers, then run npx routingcat init again.nuxt_static_preset_named:{from} names Nitro's {preset} preset, whose build writes your pages and no Worker, so nothing of RoutingCat's would run before them. Name the cloudflare_pages preset there instead, or cloudflare_module for Workers, then run npx routingcat init again.nuxt_preset_host:{from} names Nitro's {preset} preset, whose build writes nothing RoutingCat's Worker can wrap on {host}, so nothing of RoutingCat's would run before your pages. Name the {wanted} preset there instead, then run npx routingcat init again.
Fix: Set Nitro’s preset to cloudflare_pages, or cloudflare_module for Workers, whose Worker RoutingCat’s wraps, where the app names its preset, then run npx routingcat init again.
D110
Error, shown in RoutingCat’s answers, the dashboard and doctor. RoutingCat’s app embed off in a Shopify store’s published theme, never turned on there, or off in some of its markets: its pages run nothing of RoutingCat’s, and while a test’s copies are live every copy shows to every visitor.
embed_off:RoutingCat's app embed is off in {theme}, your published theme, so your store's pages run nothing of RoutingCat's and record no visit. Turn it on in the theme editor's App embeds.embed_off_copies:RoutingCat's app embed is off in {theme}, your published theme, so every copy in your tests shows to every visitor beside its original, and nothing is recorded. Turn it back on in the theme editor's App embeds, or hide the copies in the theme editor.embed_absent:RoutingCat's app embed has never been turned on in {theme}, your published theme, so your store's pages run nothing of RoutingCat's and record no visit. Turn it on in the theme editor's App embeds.embed_absent_copies:RoutingCat's app embed has never been turned on in {theme}, your published theme, so every copy in your tests shows to every visitor beside its original, and nothing is recorded. Turn it on in the theme editor's App embeds, or hide the copies in the theme editor.embed_off_markets:RoutingCat's app embed is off in {theme} for {markets}, so the visitors of those markets see every copy in your tests beside its original, and their visits are not recorded. Turn it on there in the theme editor's App embeds.
Fix: Turn RoutingCat on in the theme editor’s App embeds, from the app’s Home page in the Shopify admin, and save. Where it must stay off, hide the tests’ copies in the theme editor: pausing a test hides its copies only while the embed is on.
D111
Error, shown in RoutingCat’s answers and the dashboard. A Shopify store whose pages have posted nothing to RoutingCat for hours while a test’s copies are live: RoutingCat’s embed is not running on them, so the copies may show to every visitor.
store_silent:Your store's pages have posted nothing to RoutingCat for {hours} h (last at {last} UTC) while your tests' copies are live. If the store has traffic, RoutingCat's embed is not running on its pages, so every copy may show to every visitor beside its original. Turn RoutingCat on in the theme editor's App embeds, or hide the copies.store_silent_never:Your store's pages have posted nothing to RoutingCat in the {hours} h since your tests' copies went live. If the store has traffic, RoutingCat's embed is not running on its pages, so every copy may show to every visitor beside its original. Turn RoutingCat on in the theme editor's App embeds, or hide the copies.
Fix: If the store has traffic, RoutingCat’s embed is not running on its pages: turn it on in the theme editor’s App embeds, from the app’s Home page in the Shopify admin, or hide the tests’ copies in the theme editor.
D112
Warning, shown in RoutingCat’s answers and doctor. A Shopify store whose published theme cannot hold section tests: a vintage theme, without JSON templates, or a theme RoutingCat cannot read, such as one made in Canvas.
theme_vintage:{theme}, your published theme, is a vintage theme without JSON templates, so its sections cannot compete in a test. RoutingCat's embed still records its visits.theme_unread:RoutingCat cannot read your published theme, as happens with a theme made in Canvas, which runs no app embed yet: RoutingCat does not run on your store's pages.
Fix: Sections compete only in a theme with JSON templates, an Online Store 2.0 theme. On a vintage theme RoutingCat’s embed still records visits; move to a 2.0 theme to test its sections. A theme made in Canvas runs no app embed yet.
D113
Warning, shown in doctor. A served page shows a shared cache in front of the site, or a Cloudflare zone feature, that changes what RoutingCat’s pages run: a cache that answered without RoutingCat’s visitor cookie, Cloudflare’s Cache Everything rule among them, which strips the cookies; Rocket Loader running RoutingCat’s head snippet or core after first paint; Zaraz’s script injected before a script site’s head partial or a page’s head snippet; a zone serving the site’s pages over plain HTTP, without a redirect to https://, where RoutingCat’s Worker leaves every view undecided; a shared cache that answered a routed page rendered for one visitor’s decision, whose rc entry of version 1 names it, which shows that visitor’s variants to the next.
cache_in_front:{url} came from a cache in front of your site ({evidence}), which answered without RoutingCat's visitor cookie: visitors there get a cached copy instead of their own variants, and their visits are not recorded. Let the routed pages' HTML through that cache.cache_everything:Cloudflare's cache answered {url} ({evidence}) without RoutingCat's visitor cookie: a Cache Everything rule with an edge TTL strips RoutingCat's cookies and serves one visitor's page to the next, before RoutingCat decides. In Cloudflare's cache rules, bypass the cache for HTML on your routed paths.rocket_loader:Cloudflare's Rocket Loader runs on {url}, and RoutingCat's {script} lacks data-cfasync="false", so Rocket Loader runs it after the page shows: visitors routed there see your defaults before their own variants. Keep its tag as RoutingCat writes it, or turn Rocket Loader off for these paths with a configuration rule in Cloudflare.zaraz_first:{url}: Cloudflare's Zaraz puts its script before RoutingCat's head partial in <head>, so the partial's first decision waits for it. Turn off Zaraz's Auto-inject script for these paths in Cloudflare, and load Zaraz after the partial.zaraz_before_snippet:{url}: Cloudflare's Zaraz puts its script before RoutingCat's head snippet in <head>, so the snippet waits for it before it shows each visitor's variants. Turn off Zaraz's Auto-inject script for these paths in Cloudflare, and load Zaraz after the snippet.plain_http:{url} answers over plain HTTP, without a redirect to https://, so RoutingCat leaves the views there undecided and unrecorded: a browser keeps none of RoutingCat's cookies from an http:// page. In Cloudflare: {zone} → SSL/TLS → Edge Certificates → turn on "Always Use HTTPS".decision_cached:{url} came from a shared cache ({evidence}), though RoutingCat rendered it for one visitor's decision: the next visitors get that visitor's variants while RoutingCat records their own. Render that page at each request, without s-maxage, CDN-Cache-Control or Vercel-CDN-Cache-Control.
Fix: Let your routed pages’ HTML through every cache in front of the site, and in Cloudflare bypass the cache for HTML on those paths, since a Cache Everything rule with an edge TTL strips RoutingCat’s cookies and serves one visitor’s page to the next. Keep data-cfasync="false" on RoutingCat’s script tags as RoutingCat writes them, or turn Rocket Loader off for those paths with a configuration rule. Turn Zaraz’s Auto-inject script off on those paths, and load Zaraz after RoutingCat’s head partial or head snippet. Turn on Always Use HTTPS for the domain in Cloudflare, so that every view comes over HTTPS, where RoutingCat decides and records it. A page that shows each visitor their own variants renders at each request and stays out of shared caches: no s-maxage, CDN-Cache-Control or Vercel-CDN-Cache-Control on it, and no dynamic = 'force-static' on a Next.js page.
D114
Information, shown in init. The project’s packages show a checkout whose payments a connection reports with no code: Whop’s, or Stripe’s once the API answers that Stripe’s review has listed the Stripe App, which routingcat connect connects, or a Hydrogen storefront’s Shopify checkout, whose orders RoutingCat’s Shopify app reports to the store’s site the storefront joins.
connect_offered:Connect {provider} with no code: npx routingcat connect {connector}, run once the site exists, sends its payments to RoutingCat from {provider}'s own records, in place of a webhook recipe.shopify_orders_offered:Shopify's orders need no code: RoutingCat's Shopify app, installed in the store, sends them to RoutingCat, in place of a webhook recipe.
Fix: Connect the provider before wiring a webhook recipe for its payments: npx routingcat connect stripe or npx routingcat connect whop, once the site exists. Shopify’s orders come through RoutingCat’s Shopify app, installed in the store. A connection reports the payments from the provider’s own records.
D115
Warning, shown in push and the build log. A script site’s production push from a person’s machine, routingcat push --env production, which pushes the plan it shows once the person confirms it: at a terminal by answering, elsewhere, as under a coding agent, with --confirm and the plan’s digest, which a plan changed since no longer matches; or a production build on a person’s machine, run with ROUTINGCAT_ENV=production, which registers under their sign-in the plan it shows once they confirm it the same way, elsewhere with ROUTINGCAT_CONFIRM and the digest, and otherwise stops before the framework’s build, registering nothing.
push_confirm, exit 3:Nothing was pushed: this plan goes to production once the person confirms it. Show it to them; once they agree, run routingcat push --env production --confirm {digest}.push_confirm_stale, exit 1:Nothing was pushed: the plan confirmed as {given} has changed since, with the templates or production. Show the person this plan; once they agree, run routingcat push --env production --confirm {digest}.build_confirm, exit 3:routingcat: nothing was registered: this build's plan goes to production once the person confirms it. Show it to them; once they agree, run the build again with ROUTINGCAT_ENV=production ROUTINGCAT_CONFIRM={digest}.build_confirm_stale, exit 1:routingcat: nothing was registered: the plan confirmed as {given} has changed since, with the code or production. Show the person this plan; once they agree, run the build again with ROUTINGCAT_ENV=production ROUTINGCAT_CONFIRM={digest}.build_declined, exit 1:routingcat: nothing was registered: the plan was not confirmed, so this build stops here.build_key_ignored:routingcat: ROUTINGCAT_DEPLOY_KEY is ignored: run with ROUTINGCAT_ENV=production on your machine, this build registers under your sign-in, once you confirm its plan.build_uncommitted:This folder has changes that are not committed: the build records commit {commit}, HEAD's, not the code it deploys.build_branch:This build is of branch {branch}, not the site's production branch, {production}: confirmed, it goes to production all the same.
Fix: Show the person the plan routingcat push --env production, or the build run with ROUTINGCAT_ENV=production, printed. Once they agree, run the push again with --confirm and the digest it printed, or the build with ROUTINGCAT_CONFIRM set to it: it pushes that plan, and nothing once the code or production have changed since. With its plan, the build says when the folder holds changes not committed, or is on a branch other than the site’s production branch: it deploys them as they are once confirmed. Such a build takes the person’s sign-in alone, and says so of a ROUTINGCAT_DEPLOY_KEY it ignores.
D116
Warning, shown in doctor and link. A script site’s link to its GitHub repository, waiting for a GitHub Actions run of that repository to prove it with its OIDC token, within a day of the request, or expired before one did.
link_pending, exit 3:{site} is linked to GitHub repository {repository} once a workflow run of it proves it: run routingcat push in a workflow of {repository} whose job has permissions: id-token: write, before {until} UTC.link_expired, exit 1:The link of {site} to GitHub repository {repository} expired on {expired} UTC, before a workflow run of it proved it. Run routingcat link github again, then such a run, or routingcat unlink github.
Fix: Run routingcat push in a GitHub Actions workflow of the repository, its job with permissions: id-token: write: the run’s OIDC token proves the repository, and the push registers. Once a link has expired, run routingcat link github again before that run, or routingcat unlink github to keep the deploy key alone.
D117
Warning, shown in the build log, doctor, status and the dashboard. An Astro site on Vercel whose adapter deploys Astro’s middleware at the edge, middlewareMode: 'edge' or the older edgeMiddleware: true, in front of its pages rendered at request time: the build passes, and RoutingCat routes none of those pages, which show their defaults, since that middleware serves them past RoutingCat’s.
astro_edge_middleware:@astrojs/vercel deploys Astro's middleware at the edge, middlewareMode: 'edge', so RoutingCat routes none of your pages rendered at request time: the build passes, and those pages show your defaults until you remove middlewareMode from vercel() in your Astro config, or set it to 'classic', Astro's default.
Fix: Remove middlewareMode from vercel() in your Astro config, or set it to 'classic', Astro’s default, and remove the older edgeMiddleware: true if the config has it, then deploy: RoutingCat routes your pages rendered at request time again.
D118
Error, shown in plan, push, doctor, status and the dashboard. A page decided in the browser whose routing data for browsers RoutingCat refused to publish, past the 64 KB a Shopify store’s template may take or the 128 KB a page may take elsewhere, so that every visitor gets the page’s defaults, unrouted, until a push brings it under.
browser_bundle_refused:{page}: its routing data for browsers would take {size}, past the {limit} a page decided in the browser may take, so RoutingCat has published none for it since {time} UTC: every visitor gets the page's defaults, unrouted, until a push brings its routing data under the limit. Retire variants or turn personalization off for a slot.
Fix: A page decided in the browser takes at most 64 KB of routing data for browsers on a Shopify store, and 128 KB elsewhere; past it, every visitor gets the page’s defaults. Retire variants, merge slots or turn personalization off for a slot: RoutingCat publishes the page’s routing data again within minutes of the change.
D119
Warning, shown in status. A Shopify store’s section test whose copies change images, while a copy that shows its original’s own image, in any of the store’s section tests, shows it more than 50 ms apart from the original at the 75th percentile of the largest paint, beyond noise, over the last 7 days’ views whose largest paint lies in the slot: the delivery bias of a copy’s place in the template.
position_bias:{slot}: its copies change images, while on this store {copy} shows its original's own image {bias} ms apart from the original at the 75th percentile, from another place in the template. So this test's results may reflect where each copy sits, not only its images. Keep the original's images in the copies, or test images with RoutingCat's slot markup, which loads every variant alike.
Fix: A section’s copy loads its images by its place in the template, so it can show its largest image sooner or later than its original for that reason alone, and an image test among copies then compares places as well as images. Keep the original’s images in the copies and test their text, buttons and layout, or test images with RoutingCat’s slot markup in the theme’s code, whose variants load their images alike.
D120
Warning, shown in plan, push, the build log, doctor and status. A Next.js page that calls routingcat.decide(page) and renders static, under dynamic = 'force-static' in its file or the nearest layout that sets dynamic: Next.js renders it once for every visitor, without the decision the proxy attaches, so the deployment leaves its route unrouted and the build passes; the deployment’s registration names the route, from which status shows it while production deployments leave it so; doctor, in the project, names it where the page answers unrouted, never waiting on it.
force_static_unrouted:{file} sets dynamic = 'force-static', so Next.js renders {route} once for every visitor, without the decision RoutingCat makes for each: RoutingCat leaves {route} unrouted, and it shows your defaults. Remove that line to route it, or make {page} a static page with routingcat.decide({page}, { params }) and its wrapper route.
Fix: Remove dynamic = 'force-static' from the file the message names, so that the page renders at each request with each visitor’s variants. To keep the page static, call routingcat.decide(page, { params }) in it instead, with the wrapper route routingcat plan prints, which serves each combination of variants as its own static page.
D121
Warning, shown in status. The decisions browsers reported showing on production pages in the last 7 days whose record never reached RoutingCat exceed 1% of those reported, beyond noise: records lost on their way, which no delivery report counts, as a server’s is when its sending fails twice on an instance’s last request, or a browser’s when its visitor views no other page to send it again; one form where your servers decide the pages, another where browsers do.
decisions_unrecorded:{unrecorded} of the {named} decisions browsers reported showing in the last 7 days, {share}%, never reached RoutingCat, so their page loads are left out of every result: your servers may stop before sending them, or fail to reach RoutingCat.browser_decisions_unrecorded:{unrecorded} of the {named} decisions browsers made on your pages and reported showing in the last 7 days, {share}%, never reached RoutingCat, so their page loads are left out of every result: the browsers could not send them, and their visitors viewed no other page to send them again.
Fix: Where your servers decide, they send each decision to RoutingCat after answering the page: keep the proxy, middleware or Worker that npx routingcat init set up, which keeps that work running after the response, and let your servers’ requests to RoutingCat through any firewall or proxy. Where browsers decide, make sure nothing on your pages or in front of them, such as a Content Security Policy or a proxy, blocks the script’s requests to RoutingCat: a browser keeps a decision it could not send for the visitor’s next page, so a visitor who views one page takes it away. Run routingcat doctor, which checks your install.
D122
Warning, shown in plan, push, the build log and doctor. A routingcat.config.json whose $schema names a newer format than this routingcat reads, config-routingcat pin names a newer version than the one running, holding a key this one does not know.
config_format_newer, exit 2:{file} is written in config-{format}, which routingcat {needed} reads, and this is routingcat {version}, which reads up to config-{supported}. Run it with routingcat {needed} or later.config_pinned_newer, exit 2:{file} pins routingcat {pinned}, newer than this one, routingcat {version}, which does not know {keys}. Run it with routingcat {pinned}.
Fix: Run the command with the routingcat version the file’s $schema or its pin names, or a later one: upgrade the routingcat package to it, or, on a site that pins a version, set routingcat to it in routingcat.config.json and in your CI’s steps.
D123
Warning, shown in push and doctor. A routingcat.config.json whose $schema is not the JSON Schema of the routingcat version that runs push, https://cdn.routingcat.com/schemas/<version>/config-<n>.json, which push writes so that an editor checks the file against the release that reads it: in push –check, and in doctor (decision log entry 82).
config_schema_stale, exit 1:{file}'s $schema is not {url}, the JSON Schema of routingcat {version}, which this site runs, so an editor checks the file against another release. Run routingcat push, then commit what it changes.
Fix: Run npx routingcat push in your repository, then commit what it changes; routingcat push --check in CI fails until you do.
D124
Information, shown in the build log and doctor. A framework or library a build runs on installed at a newer major than the newest RoutingCat’s tests ran: Next.js and React for Next.js’s; Nuxt, Vue and Vite for Nuxt’s; Astro and Vite for Astro’s; React Router, React and Vite for React Router’s. Nothing refuses it, the package’s peer ranges having no upper bound: the build prints its line once and passes, and doctor names it as information.
untested_major:routingcat: RoutingCat {routingcat} was tested with {framework} up to {tested}; you have {version}. If something looks off, run npx routingcat doctor.untested_major_app:RoutingCat {routingcat} was tested with {framework} up to {tested}; this app has {version}. If something looks off, update RoutingCat once a release tested with it is out.
Fix: Nothing to fix: RoutingCat runs on a newer major as long as the framework keeps what RoutingCat uses of it. If a build or a page looks off, run npx routingcat doctor, and update RoutingCat once a release tested with that major is out.
D125
Error, shown in the build log. A Nuxt app whose server builds on Nitro 3, whose hooks routingcat/nuxt’s server plugin and build do not use: they are written for Nitro 2, the server Nuxt 4 builds by default, so the app’s server calls would send nothing and its build would register nothing; nuxt build and nuxt dev stop, and nuxt prepare, which a package manager’s install runs, prints it and goes on.
nitro_unsupported:This app's server builds on Nitro {version}, and routingcat/nuxt runs on Nitro 2, the server Nuxt 4 builds by default, so the build stops here. Build the app on Nitro 2, or remove routingcat/nuxt from nuxt.config's modules.
Fix: routingcat/nuxt runs on Nitro 2, the server Nuxt 4 builds by default. Build your app on it, or remove routingcat/nuxt from modules in nuxt.config while your app builds on Nitro 3.
D126
Warning, shown in the build log. A Nuxt app served under a base path, app.baseURL other than /, or an Astro site under its config’s base: RoutingCat matches its pages’ routes from the site’s root, so they match none of the app’s pages, which show their defaults; the build passes.
nuxt_base_url:nuxt.config serves your app under {base}, and RoutingCat matches your pages' routes from the site's root, so it routes none of them: they show your defaults. Serve the app from /, without app.baseURL, to route them.astro_base:Your Astro config serves the site under {base}, and RoutingCat matches your pages' routes from the site's root, so it routes none of them: they show your defaults. Serve the site from /, without base, to route them.
Fix: RoutingCat matches your pages by their paths from your site’s root. Serve the app from /: remove app.baseURL from nuxt.config, or base from your Astro config.
D127
Warning, shown in the build log. An Astro site whose adapter is neither @astrojs/vercel nor @astrojs/cloudflare: nothing of RoutingCat’s runs before its pages on that adapter’s host, so RoutingCat routes none of them, which show their defaults; the build passes.
astro_adapter_unsupported:Your Astro config's adapter is {adapter}, and RoutingCat runs before Astro's pages on Vercel, with @astrojs/vercel or no adapter, and on Cloudflare Workers, with @astrojs/cloudflare: deployed with {adapter}, it routes none of your pages, which show your defaults.
Fix: RoutingCat runs before an Astro site’s pages on Vercel, with @astrojs/vercel or no adapter, and on Cloudflare Workers, with @astrojs/cloudflare. Deploy the site with one of them, then run npx routingcat init again, which writes the host’s entry.
RoutingCat’s answers
Refusals and warnings in what RoutingCat answers every command, every build and the dashboard.
A1
Error, shown in RoutingCat’s answers. The sign-in or key is missing, invalid, expired or revoked, or a machine’s pairing with a Shopify store has ended: disconnected in the RoutingCat app’s Settings, unused for 30 days, or with its person’s access to the store.
unauthenticated, exit 1:RoutingCat did not accept the sign-in or key: it is missing, invalid, expired or revoked.pairing_ended, exit 1:RoutingCat no longer accepts this machine's pairing with the store: it was disconnected in the RoutingCat app's Settings, went unused for 30 days, or ended with its person's access to the store. Pair it again: run npx routingcat init in the theme's or storefront's folder, then enter the code it prints in the RoutingCat app in your Shopify admin.
Fix: unauthenticated: run npx routingcat login. For a build, check its key. pairing_ended: pair the machine with the store again from the Shopify admin: run npx routingcat init in the theme’s or storefront’s folder, then enter the code it prints in the RoutingCat app’s Settings, where the coding agent’s connection is listed.
A2
Error, shown in RoutingCat’s answers. The person or key may not do this.
denied, exit 1:{principal} is not allowed to {act} on {target}.owner_only, exit 1:Only the owner of {site} can {act}.
Fix: Use a sign-in or key allowed to do it. Only the site’s owner can change members, keys and domains.
A3
Error, shown in RoutingCat’s answers. An address or id that resolves to nothing.
not_found, exit 1:{ref} matches nothing on {site}.
Fix: Check the address or id. npx routingcat status lists what exists.
A4
Error, shown in RoutingCat’s answers. A write with --expect, made after the site changed.
version_conflict, exit 1:{site} changed since you read it (now at {current}, not {expected}), so nothing was written. Read it again, then retry.
Fix: Read the site again, then retry.
A5
Error, shown in RoutingCat’s answers. An idempotency key repeated with a different request.
idempotency_conflict, exit 1:The idempotency key {key} was already used for a different request, so this one was refused.
Fix: Use a new idempotency key, or none: the command makes one.
A6
Error, shown in RoutingCat’s answers. A malformed request or command.
invalid_request, exit 2:Invalid request: {detail}.
Fix: Fix the command’s arguments as the detail says.
A7
Error, shown in RoutingCat’s answers. A setting out of range, or one that cannot hold on the live variants.
invalid_setting, exit 1:{setting}={value} is not valid for {target}: {reason}.
Fix: Use a value within the setting’s range, and floors and caps that leave room for every live variant.
A8
Error, shown in RoutingCat’s answers. Pausing or retiring a slot’s default, which every slot needs.
default_variant, exit 1:{address} is the default of {slot}, and every slot needs its default, so it cannot be paused or retired. Promote another variant first.
Fix: Promote another variant first, then pause or retire this one.
A9
Error, shown in RoutingCat’s answers. Too many requests.
rate_limited, exit 3:Too many requests: retry in {seconds} s.
Fix: Retry after the seconds it names.
A10
Error, shown in RoutingCat’s answers. The API cannot serve the request now.
unavailable, exit 4:RoutingCat is unavailable: retry in a minute.
Fix: Retry in a minute.
A11
Error, shown in RoutingCat’s answers. The Vercel project is bound to a site you are not a member of; or, as init moves another site to it, bound to any site, since a Vercel project holds one.
project_bound, exit 1:Vercel project {project} belongs to the RoutingCat site {site}, and you are not one of its members. Ask its owner to add you.project_bound_rebind, exit 1:Vercel project {project} belongs to the RoutingCat site {bound}, so {site} is not bound to it: a Vercel project holds one site. Link this folder to another Vercel project with vercel link, then run npx routingcat init --host vercel again.
Fix: Ask the site’s owner to add you: npx routingcat members add <email>. To move a site to Vercel, link its folder to a Vercel project no other site holds, with vercel link, then run npx routingcat init --host vercel again.
A12
Error, shown in RoutingCat’s answers. A write to an archived site.
site_archived, exit 1:{site} is archived, so it takes no changes.
Fix: An archived site takes no changes.
A13
Error, shown in RoutingCat’s answers. A preview of a page with no path to show yet.
path_required, exit 1:{page} has no path to preview yet: pass one.
Fix: Pass the path to preview with --path. Without one, RoutingCat opens the page’s first route without a dynamic segment, else its most visited path of the last 7 days.
A14
Error, shown in RoutingCat’s answers. A preview of a version the production deployment does not serve yet: not deployed, or pushed while no deployment that includes it has registered, which a server’s deployment does at its first request and a script site’s at the end of its push.
not_deployed, exit 1:Your production deployment does not include {address} yet: deploy it first.not_serving, exit 1:{address} is registered, but no production deployment that includes it has registered yet: a deployment registers at its first request. Open the site, then try again; if its build failed, deploy again.not_serving_script, exit 1:{address} is registered, but no production deployment that includes it has registered yet: routingcat push registers it last, after its changes. Run it again in CI on the same templates, which registers that deployment or says why it cannot, then try again.
Fix: not_deployed: deploy the version first. not_serving: its build registered, but no deployment that includes it has had its first request yet; right after a deploy, open the site, then try again. If the build failed after registering, deploy again. not_serving_script: the site’s push registered the version, but not yet the deployment that includes it, which routingcat push registers last; run it again in CI on the same templates.
A15
Error, shown in RoutingCat’s answers. promote or preview given variants of several pages.
one_page, exit 1:{act} works on one page at a time; these variants span {pages}.
Fix: Give the variants of one page at a time.
A16
Error, shown in RoutingCat’s answers. promote or preview given several variants of one slot.
one_per_slot, exit 1:{act} takes at most one variant per slot; for {slot}, you gave {count}.
Fix: Give at most one variant per slot.
A17
Error, shown in RoutingCat’s answers. RoutingCat refuses the build’s token or deploy key.
token_refused, exit 1:routingcat: RoutingCat refused this build's token or deploy key ({reason}), so this build registers nothing and visitors get your defaults. On your machine, for a site on Cloudflare, run the build with ROUTINGCAT_ENV=production.branch_not_named, exit 1:routingcat: RoutingCat refused this build's deploy key (it is the production deploy key, bound to branch {branch}, and this build's CI names no branch), so this build registers nothing and visitors get your defaults. In a CI whose branch RoutingCat does not read, set ROUTINGCAT_BRANCH to the branch this build deploys. On your machine, for a site on Cloudflare, run the build with ROUTINGCAT_ENV=production.ci_names_no_branch, exit 1:routingcat: RoutingCat refused this build's deploy key (it is the production deploy key, bound to branch {branch}, and {ci} names no branch for this build), so this build registers nothing and visitors get your defaults. {remedy}
Fix: The build still ships, but registers nothing, so visitors get your defaults. Check ROUTINGCAT_DEPLOY_KEY, or which RoutingCat site the Vercel project belongs to. A production deploy key serves only builds of its branch, which RoutingCat reads from GitHub Actions, GitLab, Bitbucket, CircleCI, Jenkins’ multibranch pipelines, Azure Pipelines over a Git repository, Buildkite, Cloudflare’s builds, Netlify and Vercel. Where one of those names no branch for a build, as a Jenkins job outside a multibranch pipeline, ROUTINGCAT_BRANCH changes nothing: build where the CI names the branch. In any other CI, set ROUTINGCAT_BRANCH to the branch the build deploys. On your machine, for a site on Cloudflare, run the build with ROUTINGCAT_ENV=production: it registers production under your sign-in once you confirm the plan it shows.
A18
Error, shown in RoutingCat’s answers. One deployment’s build registering twice, with different declarations.
push_conflict, exit 1:{deployment} already registered different declarations, and a deployment registers only once.
Fix: A deployment registers once. Deploy again to register the new code.
A19
Error, shown in RoutingCat’s answers. Images the declarations name that the build did not upload.
asset_missing, exit 1:This build did not upload {count} of the images its variants use: {assets}.
Fix: Redeploy, so that the build uploads them.
A20
Error, shown in RoutingCat’s answers. A request body over its route’s limit.
too_large, exit 1:The request is larger than its limit, {limit}.
Fix: Send less in one request. Limits and defaults lists the limits.
A21
Error, shown in RoutingCat’s answers. revert on a page with no earlier publication.
nothing_to_revert, exit 1:{page} still serves what it went live with, so there is nothing earlier to revert to.
Fix: There is nothing earlier to return to.
A22
Information, shown in RoutingCat’s answers. A promote, which holds until a production deploy changes that default in code.
promote_holds:{slot}: {variant} is the default until a production deploy changes the default in {file}.promote_holds_markup:{slot}: {variant} is the default until a production deploy changes the default in the slot's markup. To keep it, make {variant} the variant without hidden in your templates, then run routingcat push.
Fix: Make the code follow it, so that a later deploy keeps it: set default: in the page’s file, or, in slot markup, make the promoted variant the one without hidden, then run routingcat push.
A23
Warning, shown in plan and push. More than fourteen objectives and outcomes declared.
objectives_over_limit:{count} objectives and outcomes are declared, more than the {limit} recommended.
Fix: Nothing is refused: this is a warning, not a limit. Declare only the events that matter.
A24
Warning, shown in plan and push. A path that two pages claim.
route_claimed_twice, exit 1:{route} is claimed by both {pages}; a path can belong to one page only.
Fix: A path belongs to one page: remove the route from one of them.
A25
Warning, shown in RoutingCat’s answers and status. A control below 5% of visitors.
low_control_share:The control gets {share}% of visitors, below 5%. The measured gain compares routed visits with the control, so it will take longer to measure.no_control_share:The control gets no visitors, so the measured gain can't be computed: it compares routed visits with the control.
Fix: Raise the control with npx routingcat set control_share=0.1, the default.
A26
Warning, shown in RoutingCat’s answers and status. Floors or a cap that leave routing little room in a slot.
floors_crowd_routing:{slot}: a floor of {floor}% on each of its {count} variants reserves {taken}% of its traffic, leaving routing only {left}% to favor what works.cap_at_even_split:{slot}: a cap of {cap}% is at or below an even split of its {count} variants, {even}% each, so routing cannot favor any of them.
Fix: Lower the floors, or raise the cap, so that routing can favor what works.
A27
Information, shown in init. The site key init named was taken by the time the site was created.
site_key_taken:The site key {requested} was taken by the time your site was created, so your site is {site}.
Fix: Nothing to fix: the site has the next free key, which the config init writes names: routingcat.config.ts, a JavaScript app’s routingcat.config.mjs or a template site’s routingcat.config.json.
A28
Error, shown in plan and push. Floors and caps that cannot all hold on the variants left live: each floor at most its cap, the floors together at most 100% and the caps together at least 100%.
allocation_infeasible, exit 1:{slot}: {bounds} cannot work with its {count} live variants: {reason}. Correct this in {file}.
Fix: Change the floor or the cap where the slot declares them, in its page’s file, or under slots in a template site’s routingcat.config.json, or with npx routingcat set. Each variant’s floor must be at most its cap, the floors of the live variants must add up to at most 100%, and their caps to at least 100%.
A29
Warning, shown in plan and push. An objective’s window longer than the site’s visit.
window_exceeds_episode, exit 1:{objective}: its window of {window} is longer than a visit, which lasts {episode} on this site. Shorten the window in {file}, or make visits longer first.
Fix: Shorten the window in the file, or first make visits longer with npx routingcat set episode_window=….
A30
Information, shown in plan and push. A retired variant that a production deploy declares again.
variant_returns:{address} comes back live as {version}, with its history kept.
Fix: Nothing to fix: the variant comes back live, with its history.
A31
Error, shown in RoutingCat’s answers. Turning routing on while billing holds it off: a new site waiting for its owner’s card on file, a site whose Hobby account is over its visitors a second month running, one whose Pro account is at its monthly cap, or a Shopify store without a plan, before its first choice or once its plan ended.
routing_held_by_billing, exit 1:Routing stays off on {site}: {reason}. {remedy}
Fix: For a site waiting for a card, its owner adds one in the dashboard’s Settings, Billing, nothing charged: routing starts within about 2 minutes. For a Hobby account over its visitors, subscribe to Pro there: routing comes back on for every site of the account when it subscribes. At Pro’s monthly cap, raise the cap there, or routing comes back on when the month ends. On a Shopify store, choose a plan on the RoutingCat app’s Plan page in the Shopify admin, which opens Shopify’s plan page: routing resumes once the store has one.
A32
Error, shown in RoutingCat’s answers. An act that needs Stripe (adding the card, subscribing, the customer portal) while the API’s billing settings, Stripe’s keys and prices, are not set.
billing_unavailable, exit 4:Billing is not set up yet, so {act} is unavailable.
Fix: Nothing to change on your side: billing is not set up yet on RoutingCat. Retry later, or write to support.
A33
Warning, shown in plan, push, RoutingCat’s answers and status. A deploy or an act takes a Hobby account past its 10 live variants across its sites, the slots’ defaults not counted: each variant past the 10th is registered and held, not live, and the build still succeeds.
variants_held:HELD {variants}: the Hobby plan's {limit} live variants across your sites are in use; upgrade to Pro, or retire one.store_variants_held:HELD {variants}: the {limit} live variants of your store's Hobby plan are in use; choose Pro on the RoutingCat app's Plan page in your Shopify admin, or retire one.
Fix: Upgrade to Pro in Settings, Billing, which has no limit on live variants across your sites, or retire or pause a live variant on any of them; a Shopify store, which Shopify bills, chooses Pro on the RoutingCat app’s Plan page in its Shopify admin. The held variants then go live in the order they were declared, within about 2 minutes, with no new deploy.
A34
Error, shown in RoutingCat’s answers. Creating a site past Hobby’s 3 in an account, archived and exempt sites not counted.
site_limit, exit 1:{site} was not created: the Hobby plan's {limit} sites are in use; upgrade to Pro, or archive one.
Fix: Upgrade to Pro in the dashboard’s Settings, Billing, which has no limit on sites, or archive a site you no longer use; then run init again.
A35
Warning, shown in RoutingCat’s answers, the build log and doctor. A build, or one of its instances, whose RoutingCat version cannot run beside a deployment of the site that built, started or recorded visits in the last 72 hours.
no_shared_generation:routingcat: this build's SDK, {sdk}, cannot run beside {deployment}, which runs {deployment_sdk} on {site} and counts as active until {until} UTC unless it serves visitors again, so this build registers nothing and visitors get your defaults. Deploy again after then, or build with {deployment_sdk}.
Fix: The build still ships, but registers nothing, so visitors get your defaults. Deploy again once the deployment named has served no visitor for 72 hours, or build with the RoutingCat version it runs.
A36
Error, shown in RoutingCat’s answers. Connecting a provider while RoutingCat’s settings for it are not set.
connectors_unavailable, exit 4:Connecting {provider} is not set up yet on RoutingCat, so it is unavailable.
Fix: Nothing to change on your side: this provider is not set up yet on RoutingCat. Retry later, or write to support.
A37
Error, shown in RoutingCat’s answers. An act the site of a Shopify store takes from the store’s own admin: archiving the site, which the store’s uninstall alone closes, whoever asks, adding a member by email, since a store’s people are those Shopify lets open the app, or binding the site to another host, since it stays its store’s.
shopify_bound, exit 1:{site} is the site of the Shopify store {shop}, so it is not archived here: uninstalling RoutingCat from the store's Shopify admin closes it, and deletes its data within 30 days.shopify_member_email, exit 1:{site} is the site of the Shopify store {shop}, so no one is added to it by email: its people are those Shopify lets open the RoutingCat app, and someone you removed is added back by their principal, in the app's Settings.shopify_rebind, exit 1:{site} is the site of the Shopify store {shop}, so it is bound to no other host: it stays the store's until RoutingCat is uninstalled from the store's Shopify admin.
Fix: Uninstall RoutingCat from the store’s Shopify admin, in Settings, Apps: RoutingCat then closes the store’s site, and deletes its data within 30 days, as Shopify requires. A store’s people are its staff and collaborators whom Shopify lets open the RoutingCat app; someone the owner removed is added back by their principal, in the app’s Settings. A store’s site stays bound to its store.
A38
Error, shown in RoutingCat’s answers. An operator’s deletion of a site’s records that neither the site’s archive, a Shopify store’s uninstall or redaction, nor its customer asked for.
deletion_unrequested, exit 1:{site} owes no deletion of its records: it is not archived, and no Shopify uninstall or redaction asked for one. If its customer asked, send customer_asked with a note of who asked, when and how.
Fix: Delete a site’s records once its archive or its Shopify store’s uninstall asks for it, or, when its customer asked, say so with customer_asked and a note of who asked, when and how.
A39
Error, shown in RoutingCat’s answers. A production push from a person’s machine, or a GitHub repository’s link, asked of a site bound to a host, whose builds register it; or a production build on a person’s machine asked of a site bound to a host other than a Cloudflare project.
bound_push, exit 1:{site} registers production from its build on {project}, so a push from a person's machine is refused: deploy, and the build registers it.bound_build, exit 1:{site} registers production from its build on {project}, so a production build on a person's machine is refused: deploy, and that build registers it.bound_link, exit 1:{site} is bound to {project}, whose builds prove themselves: only a script site, bound to no host, links a GitHub repository.
Fix: Deploy the site: its build registers it. A push from a person’s machine and a GitHub repository’s link are for a script site, bound to no host; a production build on a person’s machine, for a site on Cloudflare.
A40
Error, shown in RoutingCat’s answers. An operator’s act on a request about a site’s records that is done or cancelled already.
data_request_closed, exit 1:{site}'s request {request} was {state} at {at}, so nothing is left to do for it.
Fix: Act on the requests the operators’ list shows, GET /v1/operator/data-requests: a request leaves it once done or cancelled, with nothing left to do for it.
A41
Error, shown in RoutingCat’s answers. An operator’s act on a request about a site’s records that another act fulfils: data.delete the whole site’s deletion, data.redact a unit’s, a Shopify customer’s redaction or a visitor’s or an account’s that the site’s customer asked to delete, or a payment connection’s, data.return a Shopify customer’s data request.
data_request_kind, exit 1:{site}'s request {request} is {asks}, which {act} fulfils.
Fix: Run the act the request asks for: data.delete for the deletion of a whole site’s records, data.redact for a customer’s redaction or a payment connection’s records, data.return for a customer’s data request.
A42
Error, shown in RoutingCat’s answers. Starting a test on a Shopify store that Shopify bills while it has no plan: before its first choice on Shopify’s plan page, or once its subscription ended.
plan_required, exit 1:No test starts before this store has a plan: choose one on the Plan page, then start the test.
Fix: Choose a plan on the RoutingCat app’s Plan page in the Shopify admin, which opens Shopify’s plan page, then start the test.
A43
Error, shown in RoutingCat’s answers. Resuming a test on a Shopify store that Shopify bills while it has no plan, once its subscription ended: its tests are paused and its routing stopped until it chooses one.
resume_without_plan, exit 1:Choose a plan on the Plan page to resume this test.
Fix: Choose a plan on the RoutingCat app’s Plan page in the Shopify admin, which opens Shopify’s plan page. The tests the plan’s end paused resume by themselves once the store has one; resume a test a person paused from its page then.
A44
Information, shown in init. A site bound to another host, or to none, as init moves it: the binding it had ends, and no build proves the site by it any more.
binding_ended:{site} is no longer bound to {project}, so its builds there no longer register it.binding_ended_key:{site} is no longer bound to {project}, so its builds there register it only with the site's deploy key: once they stop, revoke the key with npx routingcat keys deploy --env production --revoke.
Fix: Nothing to fix once those builds stop. A Vercel project’s or a GitHub repository’s builds no longer register the site. A Cloudflare or Oxygen project’s builds register it only with the site’s deploy key, which still works there: once they stop, revoke it with npx routingcat keys deploy --env production --revoke, and give the site’s new host a key of its own with npx routingcat keys deploy --branch <your production branch> if it needs one.
A45
Warning, shown in plan, push and the build log. A route outside the route grammar, which would load and never match a visit, or match every visit: a segment written :name or *; a static segment holding [, ], : or *; [...name] or [[...name]] before the route’s last segment; or, in a route of any router but Next.js’s App Router, a route group (name) or a parallel route’s slot @name. page() and routingcat.config.json refuse such a route in the same words.
route_unmatchable, exit 1:{page}: route {route}: {reason}.
Fix: Write the route as the message says: a segment as itself, [name] for one segment that varies, [...name] for the rest of the path and [[...name]] for the rest or none, each of these two last. Only a Next.js App Router route names a route group or a slot.
A46
Warning, shown in plan and push. A deploy that identifies its variants’ content anew, after an upgrade of routingcat, names a version as a variant’s content that the content it declares does not match: the variant gets a new version, as for any change of content, though its build stated that it is the same.
rehash_unverified:{address}: its build states it is {version}'s content, but it is not, so it gets a new version.
Fix: Check that the build ran the release of routingcat your lockfile names, then deploy again. If the warning returns while the variant’s content is unchanged, report it to RoutingCat with the variant’s address.
A47
Error, shown in RoutingCat’s answers. A promotion code typed in the upgrade’s confirmation, or applied to a Pro already billed through Stripe, that cannot apply: Stripe has no active code by that name, the code has expired or reached its redemption limit, or its coupon can no longer be redeemed; its coupon is not for RoutingCat Pro; or Stripe refuses it under the code’s own terms, such as new customers only, a minimum first payment or one customer alone.
promotion_code_invalid, exit 1:The code {code} doesn't exist, has expired or has been used up.promotion_code_not_pro, exit 1:The code {code} isn't for RoutingCat Pro.promotion_code_refused, exit 1:The code {code} can't be applied to your account: {reason}.
Fix: Check the code as it was given to you: Stripe matches it whatever its case, and a code works only while it is active, before its expiry and within its redemption limit, for RoutingCat Pro and within its own terms. Ask whoever gave you the code for another, or subscribe without one.
A48
Error, shown in RoutingCat’s answers. A promotion code applied to a Pro whose subscription has a discount in force already, a code’s or one applied in Stripe’s dashboard, which a new code would replace.
discount_active, exit 1:Your Pro already has a discount {until}, so another code can't be applied.
Fix: Apply the new code once the current discount ends, on the day the dashboard’s Settings, Billing shows. To change a discount sooner, write to RoutingCat’s support.
A49
Error, shown in RoutingCat’s answers. Lowering the control below 5% of visitors without the person’s confirmation, which set passes with --confirm: below 5% the measured gain is slow to come, and at 0% it can’t be computed.
control_share_unconfirmed, exit 3:Nothing was set: a control below 5% of visitors makes the measured gain slow to come, and 0% makes it impossible, since it compares routed visits with the control. If the person wants it anyway, run again with --confirm.
Fix: Tell the person what it costs: the measured gain compares routed visits with the control, so it is slow to come below 5% of visitors, and can’t be computed at 0%. If they agree, run the same npx routingcat set again with --confirm.