reflex-dev/reflex · error · TypeError

Deserialized state is not an instance of BaseState, cannot p

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.

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)

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.