Skip to content

skip duplicate DynamicRouteVar#6202

Open
adhami3310 wants to merge 1 commit intomainfrom
skip-duplicate-DynamicRouteVar
Open

skip duplicate DynamicRouteVar#6202
adhami3310 wants to merge 1 commit intomainfrom
skip-duplicate-DynamicRouteVar

Conversation

@adhami3310
Copy link
Member

No description provided.

@codspeed-hq
Copy link

codspeed-hq bot commented Mar 21, 2026

Merging this PR will not alter performance

✅ 8 untouched benchmarks


Comparing skip-duplicate-DynamicRouteVar (eea992a) with main (7ee3026)

Open in CodSpeed

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 21, 2026

Greptile Summary

This PR adds a duplicate-registration guard to BaseState.setup_dynamic_args in reflex/state.py. When multiple routes share the same dynamic parameter name (e.g., [id] appearing in both /users/[id] and /posts/[id]), setup_dynamic_args was previously called once per route, causing the same DynamicRouteVar to be redundantly re-registered. The fix filters out any incoming arg that already exists as a DynamicRouteVar in cls.computed_vars before proceeding, short-circuiting entirely if all args are already registered.

Key changes:

  • A dict comprehension at the top of setup_dynamic_args skips args whose key is already present in cls.computed_vars as a DynamicRouteVar.
  • The existing if not args: return early-exit now also handles the case where all args were duplicates.
  • No changes to tests were included with this fix.

Minor concern:

  • The filter silently accepts the first registration of a given arg name, meaning if the same parameter name is used with a different type (SINGLE vs LIST) in a second route, the mismatch goes undetected at runtime. A warning log in that scenario would improve debuggability.

Confidence Score: 4/5

  • This PR is safe to merge; the fix correctly prevents duplicate DynamicRouteVar registrations with one minor edge-case caveat.
  • The change is small, focused, and correct for its stated purpose. The filter logic properly identifies already-registered DynamicRouteVars and skips them. The only concern is a silent type-mismatch if the same arg name is reused with different types (SINGLE vs LIST) across routes — an unlikely edge case that was already poorly handled before this PR. No regression in the common case is expected.
  • reflex/state.py — specifically the new filter block at lines 1298–1306 and its interaction with the type (SINGLE/LIST) of existing DynamicRouteVar registrations.

Important Files Changed

Filename Overview
reflex/state.py Adds a pre-filter in setup_dynamic_args to skip args already registered as DynamicRouteVar, preventing duplicate registration when multiple routes share the same dynamic param name. Logic is correct for the common case; minor concern around silent type-mismatch when the same arg name is used with different types (SINGLE vs LIST) across different routes.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["setup_dynamic_args(args)"] --> B["Filter: remove args already\nregistered as DynamicRouteVar"]
    B --> C{args empty\nafter filter?}
    C -- Yes --> D["return (no-op)"]
    C -- No --> E["_check_overwritten_dynamic_args(args)"]
    E --> F["For each remaining arg"]
    F --> G{arg type?}
    G -- SINGLE --> H["argsingle_factory(param)\n→ returns str from router.params"]
    G -- LIST --> I["arglist_factory(param)\n→ returns list[str] from router.params"]
    G -- other --> J["skip / continue"]
    H --> K["Create DynamicRouteVar"]
    I --> K
    K --> L["setattr(cls, param, dynamic_var)"]
    L --> M["Update cls.computed_vars,\ncls.vars, inherited vars"]
Loading

Last reviewed commit: "skip duplicate Dynam..."

Comment on lines +1298 to +1306
# Skip dynamic args that have already been registered by a previous route.
args = {
k: v
for k, v in args.items()
if not (
(computed_var := cls.computed_vars.get(k)) is not None
and isinstance(computed_var, DynamicRouteVar)
)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

P2 Silent type mismatch when same arg registered with different types

The filter skips any arg already registered as a DynamicRouteVar, regardless of the arg's type (SINGLE vs LIST). If two routes reuse the same parameter name but with different types — e.g., /users/[id] (SINGLE) and /posts/[...id] (LIST) — the first registration always wins silently, causing the wrong accessor (string vs. list) to be used for the second route.

Consider logging a warning when the incoming v (arg type) doesn't match the type that was used when the existing DynamicRouteVar was created, so developers are alerted to the mismatch rather than experiencing subtle runtime bugs:

# Skip dynamic args that have already been registered by a previous route.
args_to_skip = {}
new_args = {}
for k, v in args.items():
    existing = cls.computed_vars.get(k)
    if existing is not None and isinstance(existing, DynamicRouteVar):
        args_to_skip[k] = v
    else:
        new_args[k] = v

if args_to_skip:
    console.warn(
        f"Dynamic route args {list(args_to_skip)} are already registered and will be skipped."
    )
args = new_args

This is a low-likelihood edge case (same arg name with different types), but the silent failure mode is worth guarding against.

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.

1 participant