{"record":{"id":"87020c9e9c8ffdaf","repo":"3b1b/manim","slug":"trying-to-restore-without-having-saved-87020c","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/animation/transform.py","lineNumber":246,"sourceCode":"class ScaleInPlace(ApplyMethod):\n    def __init__(\n        self,\n        mobject: Mobject,\n        scale_factor: npt.ArrayLike,\n        **kwargs\n    ):\n        super().__init__(mobject.scale, scale_factor, **kwargs)\n\n\nclass ShrinkToCenter(ScaleInPlace):\n    def __init__(self, mobject: Mobject, **kwargs):\n        super().__init__(mobject, 0, **kwargs)\n\n\nclass Restore(Transform):\n    def __init__(self, mobject: Mobject, **kwargs):\n        if not hasattr(mobject, \"saved_state\") or mobject.saved_state is None:\n            raise Exception(\"Trying to restore without having saved\")\n        super().__init__(mobject, mobject.saved_state, **kwargs)\n\n\nclass ApplyFunction(Transform):\n    def __init__(\n        self,\n        function: Callable[[Mobject], Mobject],\n        mobject: Mobject,\n        **kwargs\n    ):\n        self.function = function\n        super().__init__(mobject, **kwargs)\n\n    def create_target(self) -> Mobject:\n        target = self.function(self.mobject.copy())\n        if not isinstance(target, Mobject):\n            raise Exception(\"Functions passed to ApplyFunction must return object of type Mobject\")\n        return target","sourceCodeStart":228,"sourceCodeEnd":264,"githubUrl":"https://github.com/3b1b/manim/blob/dee01804d47b9f94402d71472674710dcac125b8/manimlib/animation/transform.py#L228-L264","documentation":"Restore is a Transform that animates a mobject back to its previously saved state, held in mobject.saved_state. The constructor raises if the attribute is missing or None, i.e. save_state() was never called on that mobject.","triggerScenarios":"Playing Restore(mob) without a prior mob.save_state(); calling mob.clear_saved_state() (or mutating until saved_state is consumed) before Restore; calling save_state() on a copy and Restore on the original.","commonSituations":"Emphasize-and-restore patterns (scale up then Restore) where the initial save_state line was deleted; long construct() methods where the save happened inside a conditional branch that didn't run.","solutions":["Call mobject.save_state() before the changes you want to undo, then self.play(Restore(mobject))","Check hasattr(mobject, 'saved_state') and mobject.saved_state is not None before restoring in branching code","For one-off reversals, use Transform(mob, original_copy) with a copy you kept instead"],"exampleFix":"# before\ncircle.scale(2)\nself.play(Restore(circle))\n# after\ncircle.save_state()\ncircle.scale(2)\nself.play(Restore(circle))","handlingStrategy":"validation","validationCode":"if getattr(mobject, \"saved_state\", None) is None:\n    mobject.save_state()\nself.play(Restore(mobject))","typeGuard":"def has_saved_state(mobject) -> bool:\n    return getattr(mobject, \"saved_state\", None) is not None","tryCatchPattern":null,"preventionTips":["Call save_state() in the same statement block as the change you intend to undo","Wrap save/restore pairs in a helper method so they can't drift apart"],"tags":["animation","transform","mobject-state","validation"],"backgroundTag":null,"analyzedSha":"dee01804d47b9f94402d71472674710dcac125b8","analyzedAt":"2026-08-14T19:53:44.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}