TanStack / TanStack/router

Path params starting with `$` are rewritten to "undefined" on page load

Open
#7,598 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
15.1k
Forks
1.9k
Avg merge
1d 20h
Merged PRs (30d)
143

Description

Which project does this relate to?

Router

Describe the bug

A path param value starting with $ is destroyed on full page load: the router rewrites the URL to /files/undefined via history.replaceState and the param value becomes the string "undefined".

With pathParamsAllowedCharacters: ['$'], the router itself generates such URLs: a <Link to="/files/$filePath" params={{ filePath: '$EXAMPLE_CODE/file.abap' }}> navigates to /files/$EXAMPLE_CODE%2Ffile.abap and works fine client-side, but reloading that URL mangles it.

Claude's root cause analysis: on mount, <Transitioner> round-trips the current location through buildLocation({ to: router.latestLocation.pathname, ... }). buildLocation treats to as a route template, so interpolatePath interprets the concrete segment $EXAMPLE_CODE%2Ffile.abap as a param placeholder named EXAMPLE_CODE%2Ffile.abap.
No such param exists, so it interpolates "undefined" (encodeParam(key, params, decoder) ?? "undefined" in router-core's path.ts). The rebuilt publicHref differs from the current one, so the broken location is committed with replace: true. A second symptom of the same ambiguity: the rebuilt to containing $ doesn't exactly match any route template, so buildLocation sets destRoutes = [] and skips all search middlewares for that navigation.

Complete minimal reproducer

https://stackblitz.com/edit/github-arh22bkl?file=src%2Fmain.tsx

Steps to Reproduce the Bug
  1. npm install && npm run dev
  2. Open http://localhost:5173/ and click the link — the URL becomes /files/$EXAMPLE_CODE%2Ffile.abap and the view renders the param correctly
  3. Reload the page
  4. The URL is replaced with /files/undefined and useParams() returns filePath: "undefined"
Expected behavior

As a user, I expected a page reload of a router-generated URL to render the same route with the same param value, but the URL is rewritten to /files/undefined and the param value is lost.

Screenshots or Videos

No response

Platform
  • Router / Start Version: 1.169.2
  • OS: macOS 26.5.1
  • Browser: Chrome
  • Browser Version: 149
  • Bundler: vite
  • Bundler Version: 8.0.10 (reproduction uses vite 7 as I ran into some napi crashes in Stackblitz)
Additional context

Workaround: percent-encode $ as %24 in the pathname (e.g. via history.replaceState) before the router parses the location.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in router-core's path.ts, especially interpolatePath and the encodeParam fallback, then trace how Transitioner calls buildLocation on mount. Use the linked StackBlitz reproducer to verify the reload case, and consider regression coverage that confirms a router-generated path containing a leading $ keeps its URL and parameter value after reload.

Written by the indexing model from the issue text.

Assessment

Tech stack
react, typescript
Domain
frontend, web-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
67/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.