@k8ordo/router

Troubleshooting

Common symptoms, what causes them, and how to fix them.

On this page

Clicking a link reloads the whole page

Cause

No pattern in the route table fits the link’s path. The router takes only navigations to paths the table answers, and leaves the rest to the browser as an ordinary page load. When the app is served below a base path, it does not take paths outside that either.

Fix

Add the pattern to the route table. Build links with href and register the table on Register, and a pattern the table lacks shows up as a type error.

A link to a file shows the /* page instead of the file

Cause

The /* at the end of the route table fits every path, so the router takes a link to a file the host serves as well.

Fix

Give the link the download attribute. The browser then reports a download, and the router leaves it alone.

/products/new renders the /products/:id page

Cause

Matching walks the route table from the top and takes the first pattern that fits. With /products/:id written first, new fits :id.

Fix

Write a literal pattern such as /products/new before the :id pattern.

useParams throws “rendered under”

Cause

The pattern given to useParams is not the pattern of the page the component is rendering under. It happens in a component shared by several pages, or in a layout.

Fix

Call it in the page component, with that page’s pattern. In a component shared by several pages, read untyped params with useRoute, or check the open page with useMatch.

useRoute or useParams throws under the framework

Cause

Under @k8ordo/static and @k8ordo/server, the browser has neither the route table nor a match. Both hooks read the match <Router> holds, so they find nothing and throw.

Fix

A page receives params as a prop. To know where you are in a Client Component, use usePathname or useMatch.

usePathname throws “needs <Router> above it”

Cause

During a server render or hydration, the browser’s URL cannot be read. usePathname then reads the path <Router> or the framework’s runtime provides, and neither is above it.

Fix

Use it under <Router> or in a page the framework renders. In a host of your own built on useInterceptedNavigation, provide the path being rendered through <PathnameProvider>.

The history option has no effect on a bound navigateTo

Cause

When the pattern names a param, the second argument is always read as params, even with every param bound. Options passed second become params, and history is ignored.

Fix

Pass undefined second and the options third. With the type check in place, options in second place are a type error.

On a slow navigation, the current link changes too early

Cause

A navigation changes the URL first, and the new page appears once it is ready. usePathname and useMatch read the URL, so they return the new path while the previous page is still showing, in the same order as the address bar.

Fix

To show that a page is loading, check usePendingPathname. For a navigation you started, await navigateTo’s finished.

Nothing shows while a React.lazy page loads

Cause

An object with an error wraps the pages below in a <Suspense> whose fallback is null. A React.lazy page that suspends there never reaches a layout’s <Suspense> above, and nothing shows.

Fix

Give the same object a loading, or put a <Suspense> further down.

finished rejects with an AbortError

Cause

Another navigation started before this one finished. The overtaken navigation is abandoned, and its finished rejects with the abort reason.

Fix

Where finished can be overtaken, ignore a DOMException named AbortError and rethrow anything else.

Every button press cross-fades the whole page

Cause

The <ViewTransition> runs for transitions other than page changes. A pending action of @k8ordo/ui’s Button is a transition too.

Fix

Set the <ViewTransition>’s default to none and pass { navigation: 'auto', default: 'none' } to update. It then runs only for the navigation type the router adds.

Changing a search does not clear the error

Cause

The route table’s error clears when you move to another page. An update that changes only the query string is not a page change, so the error stays.

Fix

Call the reset the error component receives, and the page renders again in place.

A pattern the table lacks passes despite Register

Cause

The file holding the registration is not part of what TypeScript checks. Under the framework, .k8ordo starts with a dot, so naming just the directory in tsconfig.json’s include skips it.

Fix

Put the file inside what include covers. Under the framework, list the glob .k8ordo/**/*.ts in include.

k8ordo

React libraries that use Baseline features without holding back.

© 2026 k8o — MIT License

Typeset in Noto Sans JP & M PLUS 2