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

  1. Delete/clear the persisted state files (the .web states / tokens directory) so fresh state is created on next request
  2. Ensure state class names and import paths stay stable across deployments, or add pickle compatibility (e.g. __reduce__ / alias the old class path)
  3. If migrating state schema, bump/rotate the state token or add a migration step that deserializes and re-serializes state
  4. 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

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


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)