Skip to content

Do not import reflex.model while transforming an event payload - #7802

Merged
FarhanAliRaza merged 1 commit into
mainfrom
fix/no-model-import-in-event-transform
Nov 11, 2026
Merged

FarhanAliRaza merged 1 commit into
mainfrom
fix/no-model-import-in-event-transform

Conversation

@masenf

@masenf masenf commented Nov 11, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes FINDING-045 from the reflex 0.11.0a1 pre-release testing (artifacts on branch claude/vibrant-pasteur-3921g3, prerelease-testing/runs/2026-11-11-v0.11.0a1/compile_memo/ and enterprise/).

All Submissions:

  • Have you followed the guidelines stated in CONTRIBUTING.md?
  • 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?

Defect

The first event whose handler takes a dict, dataclass, TypedDict or Pydantic model argument (e.g. on_upload_progress=State.on_progress with def on_progress(self, prog: dict)) ran from reflex.model import Model inside _transform_event_arg. With the db extra installed that imports SQLAlchemy / SQLModel / alembic (0.22–0.56 s, ~143 modules) inside the event task, and the dev event-loop blocking monitor (#7672) reported the user's trivial handler as blocking the loop, with a stack through SQLAlchemy's import. Seen on an upload page and on the reflex-enterprise flow demo.

Fix

A class can only subclass rx.Model once reflex.model has run, so the payload transform now looks the module up in sys.modules instead of importing it (the pattern telemetry_accounting._get_db_model_count already uses). Apps that never use rx.Model never load SQLAlchemy, at startup or per event; apps that do loaded it when they defined their models. Per-event cost unchanged (~120 ns).

Every lazy import reachable from the event path was checked, statically and with an import audit hook on a dev server: this was the only one that ran inside an event (the next largest, plotly's to_json on the first Figure, costs 1–16 ms). Warming reflex.model at worker startup was considered and rejected: +0.22–0.32 s on every worker start and dev reload for every app with the db extra, used or not (reflex-enterprise depends on reflex[db]), and warming it in a thread can still block the first event on the import lock.

Test plan

  • tests/units/reflex_base/event/processor/test_base_state_processor.py:
    • test_transform_event_arg_dict_does_not_import_the_model_module[dict|_TagsDict|_TagsRecord] — with sys.modules["reflex.model"] = None; before: ModuleNotFoundError: import of reflex.model halted; None in sys.modules ×3.
    • test_dict_arg_handler_first_event_does_not_block_on_the_model_import — real BaseStateEventProcessor in dev with a 0.05 s threshold and a fake reflex.model whose import sleeps 0.3 s; before: the fake import ran and the monitor logged the finding's warning; after: no import, no warning, the dict reaches the handler.
    • The existing rx.Model path test still passes. The processor directory: 478 passed; the touched module: 375 passed.
  • Full unit suite: 15638 passed, 66 skipped, 81.42% (the Playwright browser-driver module excluded locally for lack of a Chromium binary). ruff, pyright: clean.
  • End to end (dev, audit hook): PyPI 0.11.0a1 logged the blocking warning on the first on_progress with 147 imports inside the event; this branch: 0 warnings, 0 imports inside events for dict / dataclass / TypedDict / Pydantic / background / upload handlers, with and without the db extra; an rx.Model argument still drops extra keys.

Notes

  • /_health lazily imports reflex.model on the loop when db_url is set (not an event); left as is.
  • Attributing import / third-party frames in the monitor is left to FINDING-046.

News fragment: packages/reflex-base/news/+dict-arg-no-model-import.bugfix.md.


Generated by Claude Code

View guided diff Turn on auto-fix

_transform_event_arg ran `from reflex.model import Model` for every dict
payload with a class annotation (dict, dataclass, TypedDict, Pydantic
model). The first such event therefore imported reflex.model, and with
the db extra SQLAlchemy/SQLModel/alembic (0.22-0.56 s, ~143 modules),
inside the event task, and the dev event-loop blocking monitor (#7672)
reported the user's trivial handler as blocking the loop.

A class can only subclass rx.Model after reflex.model has run, so look the
module up in sys.modules instead of importing it, as
telemetry_accounting._get_db_model_count already does. Apps that never use
rx.Model never load SQLAlchemy, at startup or per event, and apps that do
already loaded it when their models were defined.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dxjadq3qkhKnqZR2b9WBFi
@masenf
masenf requested a review from a team as a code owner November 11, 2026 08:28
@masenf masenf added this to the v0.11.0 milestone Nov 11, 2026
@masenf masenf added the on deck PRs lined up to review / merge next label Nov 11, 2026
@greptile-apps

greptile-apps Bot commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge.

Summary

Removes the import of reflex.model while converting event arguments.

  • Event handlers transform dictionary arguments without loading the database model package.

Reviews (1) · Last reviewed commit: "Do not import reflex.model while transfo..." · Reviewed by Greptile

@cubic-dev-ai cubic-dev-ai Bot left a comment

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.

No issues found across 3 files

View guided diff | Turn on auto-fix | Re-trigger cubic

masenf pushed a commit that referenced this pull request Nov 11, 2026
@codspeed

codspeed Bot commented Nov 11, 2026

Copy link
Copy Markdown

Merging this PR will degrade performance by 4.56%

2 warnings

⚠️ 15 benchmarks are dominated by system calls

System calls cannot be simulated consistently and are left out of the measure. The reported value understates the real cost. Switch to the Walltime instrument to measure them.

Learn more about system calls

See affected benchmarks

⚠️ 1 benchmark with a significant change ran on different hardware

Its base and head results were measured on machines with a different CPU, core count or memory, so the change might not come from the code. Run base and head on the same runner type.

Learn more about Macro Runners

See affected benchmarks

❌ 1 regressed benchmark
✅ 150 untouched benchmarks

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
❌ test_process_event_burst_independent_tokens[1] 2.7 ms 2.9 ms -4.56%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing fix/no-model-import-in-event-transform (2d3ea84) with main (2d71015)

Open in CodSpeed

@masenf

masenf commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator Author

The failing CodSpeed Performance Analysis check is not caused by this PR. The flagged benchmark, test_process_event_burst_independent_tokens[1] (−4.6 %), regresses by the same ~4.5 % on the unrelated #7797, #7800, #7801 and #7803, and CodSpeed warns that it "ran on different hardware". This diff swaps an import for a sys.modules lookup on the dict-argument path, which that benchmark (int arguments) does not take. The required performance-tests-gate passes, and the CodSpeed check is not in the required set, so it needs an acknowledgement on CodSpeed rather than a code change.


Generated by Claude Code

@FarhanAliRaza
FarhanAliRaza merged commit 68b522c into main Nov 11, 2026
169 of 171 checks passed
@FarhanAliRaza
FarhanAliRaza deleted the fix/no-model-import-in-event-transform branch November 11, 2026 13:55
masenf added a commit that referenced this pull request Nov 11, 2026
_transform_event_arg ran `from reflex.model import Model` for every dict
payload with a class annotation (dict, dataclass, TypedDict, Pydantic
model). The first such event therefore imported reflex.model, and with
the db extra SQLAlchemy/SQLModel/alembic (0.22-0.56 s, ~143 modules),
inside the event task, and the dev event-loop blocking monitor (#7672)
reported the user's trivial handler as blocking the loop.

A class can only subclass rx.Model after reflex.model has run, so look the
module up in sys.modules instead of importing it, as
telemetry_accounting._get_db_model_count already does. Apps that never use
rx.Model never load SQLAlchemy, at startup or per event, and apps that do
already loaded it when their models were defined.

Claude-Session: https://claude.ai/code/session_01Dxjadq3qkhKnqZR2b9WBFi

Co-authored-by: Claude <noreply@anthropic.com>
(cherry picked from commit 68b522c)
masenf pushed a commit that referenced this pull request Nov 11, 2026
…the train

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dxjadq3qkhKnqZR2b9WBFi
@masenf masenf added the release-train Issues found during agentic /prerelease-testing fanout, not necessarily validated bugs. label Nov 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

on deck PRs lined up to review / merge next release-train Issues found during agentic /prerelease-testing fanout, not necessarily validated bugs.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants