Describe the bug
If rxconfig.py imports a project-local module that defines an rx.State subclass, reloading the config in the same RegistrationContext crashes:
StateValueError: The substate class 'appmod____my_state' has been defined multiple times.
Shadowing substate classes is not allowed.
_get_config (packages/reflex-base/src/reflex_base/config.py) drops every recorded project-local dependency from sys.modules before each load, so the next load re-imports them and re-executes any rx.State class body they contain. The second class object collides with the first, which is still registered as a substate of its parent in the current context, and the shadowing check in State.__init_subclass__ (reflex/state.py:583) fires.
This is deterministic, not a race — it happens on every reload for such a project.
To Reproduce
Two files in a project directory:
# appmod.py
import reflex as rx
class MyState(rx.State):
value: str = ""
# rxconfig.py
import appmod # noqa: F401
import reflex as rx
config = rx.Config(app_name="statereload")
Then:
import reflex_base.config as c
from reflex_base.registry import RegistrationContext
with RegistrationContext():
c.get_config()
c.reload_config() # StateValueError
get_config(reload=True) fails the same way, since it delegates to reload_config().
Scope of the failure:
| scenario |
result |
two separate RegistrationContexts, one load each |
works — each context has its own substate registry |
reload_config() / get_config(reload=True) in one context |
StateValueError |
Expected behavior
Reloading the config re-reads rxconfig.py from disk and returns a fresh Config, without redefining states that the previous load already registered.
Specifics (please complete the following information):
- Python Version: 3.14.7
- Reflex Version: main @ 812bb47 (reflex-base 0.9.10)
- OS: Linux
Additional context
The eviction exists so that two different project directories don't reuse each other's modules — that part works and should be preserved; interleaved loads across two projects with same-named helper modules each correctly resolve their own copy.
Two directions for a fix:
- Scope the eviction to actual project changes — only drop the recorded deps when the project root differs from the one they were recorded under.
rxconfig.py itself is still evicted every load, so a reload still re-reads it. Small and contained, but a same-root reload then stops picking up edits to helper modules imported by rxconfig.py (edits to rxconfig.py itself are still picked up).
- Unregister the states before re-importing. This is what
reload_state_module (reflex/state.py) already does for hot reload, but it lives in the reflex package and reflex_base imports nothing from reflex, so it isn't reachable from config.py today. Doing it properly likely means giving RegistrationContext an unregister-by-module capability.
Noticed while reviewing #6933; it is unrelated to that PR's sys.path changes and reproduces identically on main.
Describe the bug
If
rxconfig.pyimports a project-local module that defines anrx.Statesubclass, reloading the config in the sameRegistrationContextcrashes:_get_config(packages/reflex-base/src/reflex_base/config.py) drops every recorded project-local dependency fromsys.modulesbefore each load, so the next load re-imports them and re-executes anyrx.Stateclass body they contain. The second class object collides with the first, which is still registered as a substate of its parent in the current context, and the shadowing check inState.__init_subclass__(reflex/state.py:583) fires.This is deterministic, not a race — it happens on every reload for such a project.
To Reproduce
Two files in a project directory:
Then:
get_config(reload=True)fails the same way, since it delegates toreload_config().Scope of the failure:
RegistrationContexts, one load eachreload_config()/get_config(reload=True)in one contextExpected behavior
Reloading the config re-reads
rxconfig.pyfrom disk and returns a freshConfig, without redefining states that the previous load already registered.Specifics (please complete the following information):
Additional context
The eviction exists so that two different project directories don't reuse each other's modules — that part works and should be preserved; interleaved loads across two projects with same-named helper modules each correctly resolve their own copy.
Two directions for a fix:
rxconfig.pyitself is still evicted every load, so a reload still re-reads it. Small and contained, but a same-root reload then stops picking up edits to helper modules imported byrxconfig.py(edits torxconfig.pyitself are still picked up).reload_state_module(reflex/state.py) already does for hot reload, but it lives in thereflexpackage andreflex_baseimports nothing fromreflex, so it isn't reachable fromconfig.pytoday. Doing it properly likely means givingRegistrationContextan unregister-by-module capability.Noticed while reviewing #6933; it is unrelated to that PR's
sys.pathchanges and reproduces identically onmain.