fix(exec): correct frontend URL when frontend_path lacks a leading slash (#6360)#6446
Conversation
reflex-dev#6360) Setting REFLEX_FRONTEND_PATH=noslash (no leading slash) caused startup to print: App running at: http://localhost:3001/noslash/noslash/ Root cause: urllib.parse.urljoin treats a relative path differently from an absolute one. Vite already prints the listening URL with the configured base appended (e.g. http://localhost:3001/noslash/), and joining a relative "noslash" against that doubled the segment, while a "/noslash" string would have replaced it. Extract _apply_frontend_path() that normalizes the configured path to "/path/" form before joining, so the result is independent of how the user wrote frontend_path. Add a parametrized unit test covering all slash variants and the multi-segment case. Closes reflex-dev#6360
Greptile SummaryThis PR fixes a URL-duplication bug (#6360) when Confidence Score: 4/5Safe to merge; the core bug is fixed correctly and the only concern is a minor edge-case with frontend_path="/". Only P2 findings are present. The fix is logically sound for all realistic inputs, and the test suite is thorough. The one gap (frontend_path="/") is an unlikely edge case. reflex/utils/exec.py — the Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["run_process_and_launch_url\nmatches FRONTEND_LISTENING_REGEX"] --> B["_apply_frontend_path(base_url, frontend_path)"]
B --> C{frontend_path empty?}
C -- Yes --> D[Return base_url unchanged]
C -- No --> E["normalized = '/' + frontend_path.strip('/') + '/'"]
E --> F{"stripped is empty?\ne.g. frontend_path='/'"}
F -- "Yes ⚠️" --> G["normalized = '//' → broken URL"]
F -- No --> H["urljoin(base_url, normalized)"]
H --> I[Return correctly joined URL]
D --> J["notify_frontend(url, …)"]
I --> J
Reviews (1): Last reviewed commit: "fix(exec): correct frontend URL when fro..." | Re-trigger Greptile |
| if not frontend_path: | ||
| return base_url | ||
| normalized = "/" + frontend_path.strip("/") + "/" | ||
| return urljoin(base_url, normalized) |
There was a problem hiding this comment.
Edge case:
frontend_path = "/" produces "//"
When frontend_path is exactly "/", "/".strip("/") yields "", so normalized becomes "//". Passing "//" to urljoin treats it as a network-path (protocol-relative) reference, which strips the host and produces a broken URL like "http://" instead of "http://localhost:3001/".
A simple guard handles it:
| if not frontend_path: | |
| return base_url | |
| normalized = "/" + frontend_path.strip("/") + "/" | |
| return urljoin(base_url, normalized) | |
| if not frontend_path: | |
| return base_url | |
| stripped = frontend_path.strip("/") | |
| if not stripped: | |
| return base_url | |
| normalized = "/" + stripped + "/" | |
| return urljoin(base_url, normalized) |
|
was there something wrong with #6364 |
All Submissions:
Type of change
Changes To Core Features:
closes #6360
Description
Setting
REFLEX_FRONTEND_PATH=noslash(no leading slash) caused startup to print a URL with a duplicated segment:Root cause
urllib.parse.urljointreats a relative path differently from an absolute one. Vite already prints its listening URL with the configured base appended (e.g.http://localhost:3001/noslash/), so:urljoin("http://localhost:3001/noslash/", "/noslash")returnshttp://localhost:3001/noslash(absolute path replaces).urljoin("http://localhost:3001/noslash/", "noslash")returnshttp://localhost:3001/noslash/noslash(relative path appends).Fix
Extract
_apply_frontend_path(base_url, frontend_path)inreflex/utils/exec.pythat normalizes the configured path to/path/form before joining. The result is now independent of how the user wrotefrontend_path:frontend_path"/app"http://localhost:3001/app/"app"http://localhost:3001/app/"/app/"http://localhost:3001/app/"app/v1"http://localhost:3001/app/v1/The helper is pure, so it is unit-tested directly without mocking the dev-server subprocess.
Test plan
uv run pytest tests/units/utils/test_exec.py(9 parametrized cases pass)uv run ruff check reflex/utils/exec.py tests/units/utils/test_exec.pyuv run pyright reflex/utils/exec.py tests/units/utils/test_exec.py(0 errors)REFLEX_FRONTEND_PATH=noslash reflex runnow printshttp://localhost:3001/noslash/(one segment).The new test file covers: empty path, leading-slash, no-leading-slash, trailing-slash, both-slashes, multi-segment path, and the bug scenario where vite has already baked the path into its listening URL.