3b1b/manim · error · Exception

Trying to restore without having saved

Error message

Trying to restore without having saved

What it means

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.

Source

Thrown at manimlib/animation/transform.py:246

class ScaleInPlace(ApplyMethod):
    def __init__(
        self,
        mobject: Mobject,
        scale_factor: npt.ArrayLike,
        **kwargs
    ):
        super().__init__(mobject.scale, scale_factor, **kwargs)


class ShrinkToCenter(ScaleInPlace):
    def __init__(self, mobject: Mobject, **kwargs):
        super().__init__(mobject, 0, **kwargs)


class Restore(Transform):
    def __init__(self, mobject: Mobject, **kwargs):
        if not hasattr(mobject, "saved_state") or mobject.saved_state is None:
            raise Exception("Trying to restore without having saved")
        super().__init__(mobject, mobject.saved_state, **kwargs)


class ApplyFunction(Transform):
    def __init__(
        self,
        function: Callable[[Mobject], Mobject],
        mobject: Mobject,
        **kwargs
    ):
        self.function = function
        super().__init__(mobject, **kwargs)

    def create_target(self) -> Mobject:
        target = self.function(self.mobject.copy())
        if not isinstance(target, Mobject):
            raise Exception("Functions passed to ApplyFunction must return object of type Mobject")
        return target

View on GitHub (pinned to dee01804d4)

Solutions

  1. Call mobject.save_state() before the changes you want to undo, then self.play(Restore(mobject))
  2. Check hasattr(mobject, 'saved_state') and mobject.saved_state is not None before restoring in branching code
  3. For one-off reversals, use Transform(mob, original_copy) with a copy you kept instead

Example fix

# before
circle.scale(2)
self.play(Restore(circle))
# after
circle.save_state()
circle.scale(2)
self.play(Restore(circle))
Defensive patterns

Strategy: validation

Validate before calling

if getattr(mobject, "saved_state", None) is None:
    mobject.save_state()
self.play(Restore(mobject))

Type guard

def has_saved_state(mobject) -> bool:
    return getattr(mobject, "saved_state", None) is not None

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of 3b1b/manim@dee01804d4 (2026-08-14). Data as JSON: /api/errors/87020c9e9c8ffdaf. Report an issue: GitHub.