Skip to content

match.pathname is inconsistent across nested matches with parsed path params #7731

Description

@pacexy

Which project does this relate to?

Router

Describe the bug

When a route uses params.parse and params.stringify to map a plural public URL slug to a singular internal value, nested/index matches can expose inconsistent match.pathname values.

The layout match keeps the raw URL segment, while the nested index/page match can use the parsed param value.

Reproduction

const postTypeRoute = createFileRoute("/$postType")({
  params: {
    parse: ({ postType }) => ({
      postType: postType === "articles" ? "article" : postType,
    }),
    stringify: ({ postType }) => ({
      postType: postType === "article" ? "articles" : postType,
    }),
  },
})

const postTypeIndexRoute = createFileRoute("/$postType/")({})

Visit:

/articles

Observed via useMatches():

/$postType   pathname: /articles   params.postType: article
/$postType/  pathname: /article/   params.postType: article

Expected behavior

I would expect match.pathname values in the same match chain to be consistent. Ideally both should represent the current public URL or canonical stringified URL:

/articles
/articles

At minimum, it would be helpful to document that match.pathname can contain raw or parsed params depending on match depth when path params are parsed.

Impact

This can cause duplicate or incorrect route-derived UI when using useMatches(), for example breadcrumbs, analytics paths, document metadata, or active navigation state.

Current workaround

const location = router.buildLocation({
  to: match.fullPath,
  params: match.params,
})

const canonicalHref = location.publicHref

Version

Observed with @tanstack/react-router 1.170.16.

Question

Is this inconsistency expected, or should child/index matches use the same raw/stringified path param representation as parent matches?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions