Skip to content

fix(exec): correct frontend URL when frontend_path lacks a leading slash (#6360)#6446

Open
ChinmayShringi wants to merge 1 commit intoreflex-dev:mainfrom
ChinmayShringi:fix/frontend-path-no-leading-slash-6360
Open

fix(exec): correct frontend URL when frontend_path lacks a leading slash (#6360)#6446
ChinmayShringi wants to merge 1 commit intoreflex-dev:mainfrom
ChinmayShringi:fix/frontend-path-no-leading-slash-6360

Conversation

@ChinmayShringi
Copy link
Copy Markdown

@ChinmayShringi ChinmayShringi commented May 3, 2026

All Submissions:

  • Have you followed the guidelines stated in CONTRIBUTING.md file?
  • Have you checked to ensure there aren't any other open Pull Requests for the desired changed?

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Changes To Core Features:

  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your core changes, as applicable?
  • Have you successfully ran tests with your changes locally?

closes #6360

Description

Setting REFLEX_FRONTEND_PATH=noslash (no leading slash) caused startup to print a URL with a duplicated segment:

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 its listening URL with the configured base appended (e.g. http://localhost:3001/noslash/), so:

  • urljoin("http://localhost:3001/noslash/", "/noslash") returns http://localhost:3001/noslash (absolute path replaces).
  • urljoin("http://localhost:3001/noslash/", "noslash") returns http://localhost:3001/noslash/noslash (relative path appends).

Fix

Extract _apply_frontend_path(base_url, frontend_path) in reflex/utils/exec.py that normalizes the configured path to /path/ form before joining. The result is now independent of how the user wrote frontend_path:

frontend_path Result
"/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.py
  • uv run pyright reflex/utils/exec.py tests/units/utils/test_exec.py (0 errors)
  • Manual: REFLEX_FRONTEND_PATH=noslash reflex run now prints http://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.

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
@ChinmayShringi ChinmayShringi requested a review from a team as a code owner May 3, 2026 17:57
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 3, 2026

Greptile Summary

This PR fixes a URL-duplication bug (#6360) when REFLEX_FRONTEND_PATH is set without a leading slash by introducing _apply_frontend_path, which normalises the path to /path/ form before urljoin. The fix and its parametrised tests are correct for all documented cases, but the edge case where frontend_path is exactly "/" is unhandled and would produce a broken URL.

Confidence Score: 4/5

Safe 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 _apply_frontend_path guard for a "/" input.

Important Files Changed

Filename Overview
reflex/utils/exec.py Extracts _apply_frontend_path helper to fix URL duplication bug; logic is correct for the common cases but frontend_path="/" strips to "" and produces a "//" network-path reference.
tests/units/utils/test_exec.py New unit-test file with 9 parametrised cases covering empty path, leading/trailing slash variants, multi-segment paths, and the Vite-baked-URL scenario; missing a case for frontend_path="/" which exposes the edge case above.

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
Loading

Reviews (1): Last reviewed commit: "fix(exec): correct frontend URL when fro..." | Re-trigger Greptile

Comment thread reflex/utils/exec.py
Comment on lines +179 to +182
if not frontend_path:
return base_url
normalized = "/" + frontend_path.strip("/") + "/"
return urljoin(base_url, normalized)
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.

P2 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:

Suggested change
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)

@masenf
Copy link
Copy Markdown
Collaborator

masenf commented May 4, 2026

was there something wrong with #6364

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.

frontend_path without a leading slash results in incorrect message printed

2 participants