reflex-dev/reflex · error · TypeError
Deserialized state is not an instance of BaseState, cannot…
Error message
Deserialized state is not an instance of BaseState, cannot populate substates.
What it means
When loading persisted state from disk, the pickled root object retrieved for a token was not an instance of BaseState. The disk state manager can only repopulate a state tree from a deserialized BaseState, so it raises TypeError rather than corrupting the state tree. This usually means the on-disk pickle is stale, corrupted, or was written by an incompatible version/class definition of the state classes.
Solutions
- Delete/clear the persisted state files (the .web states / tokens directory) so fresh state is created on next request
- Ensure state class names and import paths stay stable across deployments, or add pickle compatibility (e.g. __reduce__ / alias the old class path)
- If migrating state schema, bump/rotate the state token or add a migration step that deserializes and re-serializes state
- Catch TypeError in custom middleware and fall back to creating a fresh root state for the token
Example fix
# before: stale pickle on disk causes TypeError on next request
await app.state_manager.get_state(token)
# after: clear persisted state so a fresh tree is created
import shutil; shutil.rmtree(".web/_states", ignore_errors=True)
await app.state_manager.get_state(token) Defensive patterns
Strategy: try-catch
Validate before calling
root = pickle.loads(data) if data else None
if root is not None and not isinstance(root, rx.BaseState):
# discard and start fresh instead of calling get_state on it
root = None Type guard
def is_valid_root_state(obj: object) -> TypeGuard[rx.BaseState]:
return isinstance(obj, rx.BaseState) Try / catch
try:
state = await app.state_manager.get_state(token)
except TypeError as e:
if "not an instance of BaseState" in str(e):
# clear stale persisted state and retry with fresh state
state = None # let manager create fresh root
else:
raise Prevention
- Keep state class names and import paths stable across deployments
- Add a schema/version field to state and validate it after unpickling
- Clear persisted state directories as part of breaking-change deployments
When it happens
Trigger: Calling state_manager.get_state(token) (directly or via modify_state) with a DiskStateManager when the pickled file for that token contains an object that unpickles to something other than a BaseState subclass — e.g. after renaming/moving state classes, changing class hierarchy, or a truncated/corrupt pickle file in the .web states directory.
Common situations: Refactoring state classes (rename/move) so old pickles resolve to plain objects or fail isinstance checks; deploying a new app version against a stale .web/_state directory; manually tampering with token files; crashes mid-write leaving a partial pickle.
Related errors
- Component must have a library to bundle.
- Cannot determine dependencies in fetched state
- Cannot directly call background task
- ChildrenTypeError(component=cls.__name__, child=child)
- ComputedVar dependencies must be Var instances or var names…
AI-assisted analysis of reflex-dev/reflex@45b8ed5ab7 (2026-08-28).
Data as JSON: /api/errors/a160ef1d50fc6369.
Report an issue: GitHub.
Appendix: source
Thrown at reflex/istate/manager/disk.py:195
token = self._coerce_token(token)
root_state = self.states.get(token.cache_key)
self._token_last_touched[token.cache_key] = time.time()
if root_state is not None:
# Retrieved state from memory.
return root_state
# Deserialize root state from disk.
if isinstance(token, BaseStateToken):
# Find the root state
root_state_cls = token.cls.get_root_state()
root_state = await self.load_state(token.with_cls(root_state_cls))
# Create a new root state tree with all substates instantiated.
fresh_root_state = root_state_cls(_reflex_internal_init=True)
if root_state is None:
root_state = fresh_root_state
elif not isinstance(root_state, BaseState):
msg = "Deserialized state is not an instance of BaseState, cannot populate substates."
raise TypeError(msg)
else:
# Ensure all substates exist, even if they were not serialized previously.
root_state.substates = fresh_root_state.substates
await self.populate_substates(token, root_state, root_state)
self.states[token.cache_key] = root_state
return cast(TOKEN_TYPE, root_state)
# For non-BaseState tokens, if the deserialized state is None, we create a new instance using the token's cls.
state = await self.load_state(token)
if state is None:
state = token.cls()
self.states[token.cache_key] = state
return cast(TOKEN_TYPE, state)
async def set_state_for_substate(
self, token: StateToken[TOKEN_TYPE], substate: TOKEN_TYPE
):
"""Set the state for a substate.
View on GitHub (pinned to 45b8ed5ab7)