Skip to content

fix: matchConfigPattern incorrectly matches :param with literal suffix#191

Merged
southpolesteve merged 1 commit intocloudflare:mainfrom
jokull:fix/config-pattern-param-suffix
Mar 2, 2026
Merged

fix: matchConfigPattern incorrectly matches :param with literal suffix#191
southpolesteve merged 1 commit intocloudflare:mainfrom
jokull:fix/config-pattern-param-suffix

Conversation

@jokull
Copy link
Copy Markdown
Contributor

@jokull jokull commented Feb 28, 2026

Summary

  • Patterns like /:slug.md fell through to the simple segment matcher, which treated slug.md as the entire parameter name and matched any single-segment path (including /)
  • This caused rewrites like { source: "/:slug.md", destination: "/api/markdown/:slug" } to rewrite every page request, resulting in 404s on all routes
  • Added /:[\w-]+\./.test(pattern) to the condition that triggers the regex-based matcher, which already tokenizes :slug + . + md correctly

Test plan

  • Added unit tests for /:slug.md pattern via both index.ts and config/config-matchers.ts
  • All 18 existing matchConfigPattern tests pass (no regressions)
  • Verified with a real app: GET / returns 200 with HTML (was 404 before)

🤖 Generated with Claude Code

Patterns like `/:slug.md` were falling through to the simple segment
matcher, which treated `slug.md` as the entire parameter name and
matched any single-segment path (including `/`). This caused rewrites
like `{ source: "/:slug.md", destination: "/api/markdown/:slug" }` to
rewrite every page request, resulting in 404s.

Add `/:[\w-]+\./.test(pattern)` to the condition that triggers the
regex-based matcher, which already tokenizes `:slug` + `.` + `md`
correctly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@southpolesteve
Copy link
Copy Markdown
Collaborator

/bigbonk review this. Check that we are matching NextJS behavior

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Mar 2, 2026

Open in StackBlitz

npm i https://pkg.pr.new/vinext@191

commit: b5336d1

Copy link
Copy Markdown
Contributor

@ask-bonk ask-bonk Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good bug fix. The root cause analysis is correct — patterns like /:slug.md fell through to the simple segment matcher, which treated slug.md as the entire param name and matched any single segment regardless of suffix.

The fix is minimal and correct: adding /:[\ w-]+\./.test(pattern) to the regex-branch guard ensures these patterns are handled by the tokenizer/regex path, which already knows how to decompose :slug + . + md into the right regex (^/([^/]+)\.md$).

I verified:

  • The tokenizer in config-matchers.ts and index.ts correctly splits /:slug.md into tokens :slug, ., md → regex ([^/]+)\.md
  • The chained-replace approach in app-dev-server.ts also works correctly since .replace(/\./g, '\\.') runs first, then :slug([^/]+), producing the same final regex
  • prod-server.ts imports from config-matchers.ts, so it gets the fix automatically — no separate change needed
  • The new guard regex has no false positives on patterns without dots (e.g. /:slug, /path/:slug)
  • All three copies (config-matchers.ts, index.ts, app-dev-server.ts) are updated consistently

Two minor observations below, neither blocking.

pattern.includes("\\") ||
/:[\w-]+[*+][^/]/.test(pattern)
/:[\w-]+[*+][^/]/.test(pattern) ||
/:[\w-]+\./.test(pattern)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: The existing copies of matchConfigPattern in index.ts and app-dev-server.ts are a maintenance risk — this PR is a good example of needing to patch 3 places. Not something to fix in this PR, but worth noting for a future dedup effort.

Comment thread tests/shims.test.ts
"../packages/vinext/src/index.js"
);
// Should match URLs with the .md suffix and extract the param
expect(matchConfigPattern("/hello-world.md", "/:slug.md")).toEqual({ slug: "hello-world" });
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice coverage. One edge case that might be worth adding in a follow-up: a pattern with multiple dots like /:file.tar.gz — the tokenizer would produce ([^/]+)\.tar\.gz which is correct, but an explicit test would document that behavior.

@ask-bonk
Copy link
Copy Markdown
Contributor

ask-bonk Bot commented Mar 2, 2026

fatal: could not read Username for 'https://github.com': No such device or address

github run

@ask-bonk
Copy link
Copy Markdown
Contributor

ask-bonk Bot commented Mar 2, 2026

@southpolesteve Bonk workflow failed. Check the logs for details.

View workflow run · To retry, trigger Bonk again.

@southpolesteve southpolesteve merged commit f56b14d into cloudflare:main Mar 2, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants