fix(route): don't let a splat catchall match paths sharing its prefix#6790
fix(route): don't let a splat catchall match paths sharing its prefix#6790chuenchen309 wants to merge 2 commits into
Conversation
The catchall segment compiled to a bare `.*` with no separator, so `posts/[[...splat]]` became `^/posts.*/?$` and matched `/postsomething`. The frontend maps the same route to React Router's `posts/*`, which matches the route and its descendants only, so a request could resolve to a different page's on_load events than the page actually rendered. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Greptile SummaryFixes a regex mismatch in
Confidence Score: 5/5Safe to merge β the change is a single targeted regex fix backed by a focused, parameterized test suite that was verified red-before/green-after. The fix is minimal (one regex fragment), correct against both the Python fullmatch call and React Router's posts/* semantics, and the added tests exercise all the important cases including the two paths that previously matched incorrectly. No other call sites are affected and no pre-existing functionality is disturbed. No files require special attention. Important Files Changed
Reviews (1): Last reviewed commit: "Add changelog fragment for #6790" | Re-trigger Greptile |
Problem
get_route_regexcompiles the splat catchall to a bare.*with no separator in front of it, while every other segment type prepends/. Soposts/[[...splat]]becomes^/posts.*/?$, which matches any path that merely starts with the literal text:Why the second two are wrong
Not a judgement call β the frontend disagrees with it.
_embed_manifest_path_for(packages/reflex-base/src/reflex_base/plugins/embed.py:42-73) maps[[...splat]]to React Router's*, so the same route compiles toposts/*, which matches/postsand its descendants but not/postsomething. The Python router and the router that actually renders the page were answering differently for the same path.Impact
app.routerfeedsget_load_events(app.py:1038), called per page load fromstate.py:2467, andapp.py:1804(self.app.router(path) or "404"). A path resolving to the wrong route means a different page'son_loadevents fire than the page that renders.Fix
.*β(/.*)?, making the separator required while keeping the zero-segment case (/postsitself) matching.I probed the other segment types against React Router's semantics before changing anything β single, optional, and index all already agree, so the catchall was the only divergence.
Tests
test_get_router_splat_catchallintests/units/test_route.py, parameterized over both the matching and non-matching cases. Verified red before the fix (the two prefix cases fail, the three legitimate ones pass), green after.uv run pytest tests/unitsβ 4340 passed.uv run ruff check ./ruff format --checkclean,uv run pyright reflex testsβ 0 errors. (tests/units/istate/manager/test_expiration.pyis flaky onmainindependently of this change β it fails ~2 runs in 5 on a pristine checkout.)AI assistance
Written with Claude Code. I verified the repro, the React Router mapping, and the pre-existing flake myself rather than taking them on the model's word, and I'm responsible for the contents.