{"record":{"id":"020f82719579a309","repo":"3b1b/manim","slug":"trying-to-restore-without-having-saved","errorCode":null,"errorMessage":"Trying to restore without having saved","messagePattern":"Trying to restore without having saved","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"manimlib/mobject/mobject.py","lineNumber":685,"sourceCode":"                if value in family:\n                    setattr(result, attr, result.family[family.index(value)])\n            elif isinstance(value, np.ndarray):\n                setattr(result, attr, value.copy())\n        return result\n\n    def generate_target(self, use_deepcopy: bool = False) -> Self:\n        self.target = self.copy(deep=use_deepcopy)\n        self.target.saved_state = self.saved_state\n        return self.target\n\n    def save_state(self, use_deepcopy: bool = False) -> Self:\n        self.saved_state = self.copy(deep=use_deepcopy)\n        self.saved_state.target = self.target\n        return self\n\n    def restore(self) -> Self:\n        if not hasattr(self, \"saved_state\") or self.saved_state is None:\n            raise Exception(\"Trying to restore without having saved\")\n        self.become(self.saved_state)\n        return self\n\n    def become(self, mobject: Mobject, match_updaters=False) -> Self:\n        \"\"\"\n        Edit all data and submobjects to be idential\n        to another mobject\n        \"\"\"\n        self.align_family(mobject)\n        family1 = self.get_family()\n        family2 = mobject.get_family()\n        for sm1, sm2 in zip(family1, family2):\n            sm1.set_data(sm2.data)\n            sm1.set_uniforms(sm2.uniforms)\n            sm1.bounding_box[:] = sm2.bounding_box\n            sm1.pointlike_uniform_keys = sm2.pointlike_uniform_keys\n            sm1.shader_file = sm2.shader_file\n            sm1.texture_paths = sm2.texture_paths","sourceCodeStart":667,"sourceCodeEnd":703,"githubUrl":"https://github.com/3b1b/manim/blob/dee01804d47b9f94402d71472674710dcac125b8/manimlib/mobject/mobject.py#L667-L703","documentation":"Exception('Trying to restore without having saved') raised by Mobject.restore (manimlib/mobject/mobject.py:685). restore() copies a previously captured snapshot via self.become(self.saved_state); if save_state() was never called (or saved_state is None), there is nothing to restore, so manim refuses instead of silently no-op'ing.","triggerScenarios":"Calling mob.restore() before any mob.save_state(); accessing the Restore animation (self.play(Restore(mob))) without a prior save_state(); calling restore() twice after resetting saved_state to None.","commonSituations":"Classic manim pattern `mob.save_state(); mob.transform...; self.play(Restore(mob))` where the first line was dropped during a refactor; reusing a mobject across scenes where the state was never saved in the new scene; code copied from examples without the save_state line.","solutions":["Call mob.save_state() once before mutating the mobject, then mob.restore() (or self.play(Restore(mob))) later","Guard with hasattr: if getattr(mob, 'saved_state', None): mob.restore()","If you just want a copy to return to, use generate_target()/target-based Transform instead"],"exampleFix":"# before\nmob.shift(RIGHT * 2)\nself.play(Restore(mob))  # raises: restore without having saved\n\n# after\nmob.save_state()\nmob.shift(RIGHT * 2)\nself.play(Restore(mob))","handlingStrategy":"validation","validationCode":"if getattr(mob, 'saved_state', None) is None:\n    mob.save_state()\nmob.restore()","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pair save_state() with restore()/Restore() in the same function","Treat Restore animations as invalid unless save_state appears earlier in the scene"],"tags":["manim","mobject","state-management","animation"],"backgroundTag":null,"analyzedSha":"dee01804d47b9f94402d71472674710dcac125b8","analyzedAt":"2026-08-14T19:53:44.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}