diff --git a/reflex/state.py b/reflex/state.py index cda36a0a9..d7cfcf18b 100644 --- a/reflex/state.py +++ b/reflex/state.py @@ -1277,6 +1277,9 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): self._mark_dirty() return + if not name in self.vars and not name in self._computed_var_dependencies and not name in self.get_skip_vars(): + raise AttributeError(f"The state var '{name}' has not been defined in '{type(self).__name__}'. All state vars must be declared before they can be set.") + # Set the attribute. super().__setattr__(name, value) diff --git a/tests/units/test_state.py b/tests/units/test_state.py index 205162b9f..b85116101 100644 --- a/tests/units/test_state.py +++ b/tests/units/test_state.py @@ -3262,3 +3262,26 @@ def test_child_mixin_state() -> None: assert "computed" in ChildUsesMixinState.inherited_vars assert "computed" not in ChildUsesMixinState.computed_vars + + +def test_assignment_to_undeclared_vars(): + """Test that an attribute error is thrown when undeclared vars are set""" + class State(BaseState): + val: str + + def handle(self): + self.num = 5 + + class Substate(State): + + def handle_var(self): + self.value = 20 + + state = State() + sub_state = Substate() + + with pytest.raises(AttributeError): + state.handle() + + with pytest.raises(AttributeError): + sub_state.handle()