Prod mode serves HTTP 404 status for direct loads of valid dynamic-route URLs (SPA fallback body renders fine)
@FarhanAliRaza is already working on this.
Since Aug 28, 2026.
Assessment
This issue has not been assessed yet.
Description
Describe the bug
In self-hosted prod (reflex run --env prod), a direct load of any dynamic-route URL returns HTTP status 404 with the SPA-fallback HTML as the body; the page then renders correctly client-side. Valid dynamic URLs and genuinely unknown paths are indistinguishable at the HTTP layer (byte-identical bodies, same status). Static routes behave differently: they 307-redirect to .../ and then 200.
Filing this as a behavior/docs question rather than a straight bug: is the 404 status for valid dynamic routes intended (accepted SPA-fallback tradeoff to be documented as a known limitation), or should the status code be fixed? Bad for SEO, uptime monitors, and anything that trusts status codes.
To Reproduce
App with pages /, /other, /articles/[id], /posts/[[...splat]]:
reflex run --env prod --frontend-port 8604 --backend-port 8604
curl -sS -o /dev/null -w '%{http_code}\n' http://localhost:8604/ # 200
curl -sS -o /dev/null -w '%{http_code}\n' -L http://localhost:8604/other # 307 -> 200
curl -sS -o /dev/null -w '%{http_code}\n' http://localhost:8604/articles/7 # 404 (renders fine in browser)
curl -sS -o /dev/null -w '%{http_code}\n' http://localhost:8604/posts/a/b # 404 (renders fine in browser)
curl -sS -o /dev/null -w '%{http_code}\n' http://localhost:8604/definitely-not-a-page # 404, same body
Browser check (document response status): /articles/7 -> status 404, renders the correct article page.
Observed behavior
All dynamic-route direct loads return status 404 with a body byte-identical to .web/build/client/404.html; true 404s return the same thing.
Expected behavior
Valid, routable URLs return 200 (the prod backend knows the route table — app.router(path) — so the static mount could serve the fallback with 200 for routable paths and reserve 404 for genuinely unknown ones); or the current behavior is documented as a known limitation of the SPA-fallback serving model.
Root cause (from source)
Prod mode mounts the built frontend with Starlette StaticFiles(html=True) (get_frontend_mount -> PrecompressedStaticFiles), and the build step copies the react-router SPA fallback (__spa-fallback.html) over 404.html (build.py: path_ops.cp(spa_fallback, static_dir / "404.html")). Starlette's html=True semantics serve 404.html with status 404 for any path that maps to no file; dynamic routes are never prerendered to files, so they always take this path. Static pages exist as <route>/index.html dirs, hence the 307 -> 200.
Specifics (please complete the following information):
- Python Version: 3.11
- Reflex Version: 0.9.9a1
- OS: linux
- Browser (Optional): Chromium
Additional context
- Pre-existing: identical curl/browser matrix on 0.9.8 — NOT a 0.9.9 regression.
- Closely related to #6463 (soft 404: 200 for non-existent routes) — same underlying "SPA fallback does double duty" design; this is the mirror-image symptom on the self-hosted
StaticFiles(html=True)path, and a route-table-aware fix would resolve both. - Found during 0.9.9a1 pre-release testing; repro app and status matrices are on branch
claude/reflex-prerelease-testing-t0sd90underprerelease-testing/2026-08-27-v0.9.9a1/routing/.
- Dominant language
- Python
- Stars
- 28.9k
- Forks
- 1.8k
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 173
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from reflex-dev/reflex
-
Difficulty 1/5 1-3 hours Newbie friendliness 78/100
reflex-dev/reflex#7149 · 1 comment ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
reflex-dev/reflex#7148 · 1 comment ·
-
Difficulty 1/5 Under an hour Newbie friendliness 85/100
reflex-dev/reflex#7103 · 1 comment ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
reflex-dev/reflex#6823 · 1 comment ·
-
support redis v8 Openfeature request
Difficulty 1/5 Under an hour Newbie friendliness 88/100
reflex-dev/reflex#6764 · 3 comments · 1 reaction ·
All issues in reflex-dev/reflex
Similar issues
-
triage/confirmed
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
agentscope-ai/agentscope#2775 ·
-
comp/desktop P3 type/bug
Difficulty 1/5 Under an hour Newbie friendliness 92/100
NousResearch/hermes-agent#118866 ·
-
bug
Difficulty 1/5 Under an hour Newbie friendliness 90/100
apache/cloudstack#14222 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 82/100