You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
enable_state=False guard (code_uses_state_contexts) misses memoized state reads #7579
code_uses_state_contexts (reflex/state.py) is a compile-time guard for rx.App(enable_state=False). It searches the generated page JS for the substring useContext(StateContexts. If it finds the substring, compile_app raises:
To access rx.State in frontend components, at least one subclass of rx.State must be defined in the app.
The guard is blind in the common case. Auto-memoization moves state reads out of the page module into memo modules. The guard checks only page output, so it does not see these reads.
Expected: ReflexRuntimeError ("To access rx.State in frontend components ...").
Actual: Success: App compiled successfully. The app then fails at runtime.
Why it matters
The guard depends on the exact text of a generated hook. Any change to the hook string breaks it without a test failure. fix: flatten providers for large state trees #7441 must change the substring to useStateContext( only to keep this guard in sync.
It gives a false sense of safety. It fires only for the few state reads that stay in the page module.
Proposal
Pick one:
Delete code_uses_state_contexts, its call site in compile_app, and its tests. Since auto-memoization, the guard almost never fires.
Replace it with a structural check: collect VarData.state from the compiled hooks of pages and memo components. Raise when any state is referenced and app._state is None. Do not match substrings of generated JS.
Confirmed through the real compiler API, compile_app(app, dry_run=True, use_rich=False), on main 7a1de653fb9746a5d905ac422eb5bec3f3219ba4 and #7441 head 3084bc4828cafc36ee8bfd1ec80306be5982e1e1. The reported example returns True with app._state is None on both. The state read is emitted in a memo, while both page outputs miss the guard. The same read with state enabled, and a genuinely static page with state disabled, compile successfully. These checks exercised compiler output; they did not validate the CLI or browser runtime.
Two additional observations:
The string check also rejects a completely stateless page. On the tested main revision, this app raises ReflexRuntimeError through the compiler API:
Collecting VarData.state from compiled hooks alone still misses the reported example. Its emitted memo hook has state == "". Component._get_vars_hooks replaces the originating VarData with position-only metadata when building hook entries. The dependency exists earlier in the originating VarData, as created by VarData.from_state.
I recommend structural validation that collects dependencies from originating Vars during component/memo compilation, or deliberately preserves that metadata, before JS emission. Include pages, explicit and automatic memos, prop-embedded components, app wraps and hydrate fallbacks. The current guard runs before app-wrap and fallback memos are registered, so moving the check to all final compilation domains matters too.
Regression coverage should include the missed memo read, nonmemoized reads, literal text containing either hook spelling, and valid stateless/client-only-hook and state-enabled controls. The diagnostic should explain disabled state: the original reproduction already defines a State subclass. Removing the guard would leave the unsupported state use to fail later.
Activity
linear-code commentedon Oct 15, 2026
ENG-13362
masenf commentedon Oct 15, 2026
Confirmed through the real compiler API,
compile_app(app, dry_run=True, use_rich=False), on main7a1de653fb9746a5d905ac422eb5bec3f3219ba4and #7441 head3084bc4828cafc36ee8bfd1ec80306be5982e1e1. The reported example returnsTruewithapp._state is Noneon both. The state read is emitted in a memo, while both page outputs miss the guard. The same read with state enabled, and a genuinely static page with state disabled, compile successfully. These checks exercised compiler output; they did not validate the CLI or browser runtime.Two additional observations:
ReflexRuntimeErrorthrough the compiler API:VarData.statefrom compiled hooks alone still misses the reported example. Its emitted memo hook hasstate == "".Component._get_vars_hooksreplaces the originating VarData with position-only metadata when building hook entries. The dependency exists earlier in the originating VarData, as created byVarData.from_state.I recommend structural validation that collects dependencies from originating Vars during component/memo compilation, or deliberately preserves that metadata, before JS emission. Include pages, explicit and automatic memos, prop-embedded components, app wraps and hydrate fallbacks. The current guard runs before app-wrap and fallback memos are registered, so moving the check to all final compilation domains matters too.
Regression coverage should include the missed memo read, nonmemoized reads, literal text containing either hook spelling, and valid stateless/client-only-hook and state-enabled controls. The diagnostic should explain disabled state: the original reproduction already defines a State subclass. Removing the guard would leave the unsupported state use to fail later.