{"record":{"id":"a160ef1d50fc6369","repo":"reflex-dev/reflex","slug":"deserialized-state-is-not-an-instance-of-basestate","errorCode":null,"errorMessage":"Deserialized state is not an instance of BaseState, cannot populate substates.","messagePattern":"Deserialized state is not an instance of BaseState, cannot populate substates\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"reflex/istate/manager/disk.py","lineNumber":195,"sourceCode":"        token = self._coerce_token(token)\n        root_state = self.states.get(token.cache_key)\n        self._token_last_touched[token.cache_key] = time.time()\n        if root_state is not None:\n            # Retrieved state from memory.\n            return root_state\n\n        # Deserialize root state from disk.\n        if isinstance(token, BaseStateToken):\n            # Find the root state\n            root_state_cls = token.cls.get_root_state()\n            root_state = await self.load_state(token.with_cls(root_state_cls))\n            # Create a new root state tree with all substates instantiated.\n            fresh_root_state = root_state_cls(_reflex_internal_init=True)\n            if root_state is None:\n                root_state = fresh_root_state\n            elif not isinstance(root_state, BaseState):\n                msg = \"Deserialized state is not an instance of BaseState, cannot populate substates.\"\n                raise TypeError(msg)\n            else:\n                # Ensure all substates exist, even if they were not serialized previously.\n                root_state.substates = fresh_root_state.substates\n            await self.populate_substates(token, root_state, root_state)\n            self.states[token.cache_key] = root_state\n            return cast(TOKEN_TYPE, root_state)\n        # For non-BaseState tokens, if the deserialized state is None, we create a new instance using the token's cls.\n        state = await self.load_state(token)\n        if state is None:\n            state = token.cls()\n        self.states[token.cache_key] = state\n        return cast(TOKEN_TYPE, state)\n\n    async def set_state_for_substate(\n        self, token: StateToken[TOKEN_TYPE], substate: TOKEN_TYPE\n    ):\n        \"\"\"Set the state for a substate.\n","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/reflex-dev/reflex/blob/45b8ed5ab735f8a56bbb09a42384f030eb0208e7/reflex/istate/manager/disk.py#L177-L213","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before: stale pickle on disk causes TypeError on next request\nawait app.state_manager.get_state(token)\n\n# after: clear persisted state so a fresh tree is created\nimport shutil; shutil.rmtree(\".web/_states\", ignore_errors=True)\nawait app.state_manager.get_state(token)","handlingStrategy":"try-catch","validationCode":"root = pickle.loads(data) if data else None\nif root is not None and not isinstance(root, rx.BaseState):\n    # discard and start fresh instead of calling get_state on it\n    root = None","typeGuard":"def is_valid_root_state(obj: object) -> TypeGuard[rx.BaseState]:\n    return isinstance(obj, rx.BaseState)","tryCatchPattern":"try:\n    state = await app.state_manager.get_state(token)\nexcept TypeError as e:\n    if \"not an instance of BaseState\" in str(e):\n        # clear stale persisted state and retry with fresh state\n        state = None  # let manager create fresh root\n    else:\n        raise","preventionTips":["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"],"tags":["reflex","state","pickle","disk-persistence","type-mismatch"],"backgroundTag":"deserialization-type-mismatch","analyzedSha":"45b8ed5ab735f8a56bbb09a42384f030eb0208e7","analyzedAt":"2026-08-28T19:25:27.644Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}