3b1b/manim · error · Exception
Trying to restore without having saved
Error message
Trying to restore without having saved
What it means
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.
Source
Thrown at manimlib/mobject/mobject.py:685
if value in family:
setattr(result, attr, result.family[family.index(value)])
elif isinstance(value, np.ndarray):
setattr(result, attr, value.copy())
return result
def generate_target(self, use_deepcopy: bool = False) -> Self:
self.target = self.copy(deep=use_deepcopy)
self.target.saved_state = self.saved_state
return self.target
def save_state(self, use_deepcopy: bool = False) -> Self:
self.saved_state = self.copy(deep=use_deepcopy)
self.saved_state.target = self.target
return self
def restore(self) -> Self:
if not hasattr(self, "saved_state") or self.saved_state is None:
raise Exception("Trying to restore without having saved")
self.become(self.saved_state)
return self
def become(self, mobject: Mobject, match_updaters=False) -> Self:
"""
Edit all data and submobjects to be idential
to another mobject
"""
self.align_family(mobject)
family1 = self.get_family()
family2 = mobject.get_family()
for sm1, sm2 in zip(family1, family2):
sm1.set_data(sm2.data)
sm1.set_uniforms(sm2.uniforms)
sm1.bounding_box[:] = sm2.bounding_box
sm1.pointlike_uniform_keys = sm2.pointlike_uniform_keys
sm1.shader_file = sm2.shader_file
sm1.texture_paths = sm2.texture_pathsView on GitHub (pinned to dee01804d4)
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
Example fix
# before mob.shift(RIGHT * 2) self.play(Restore(mob)) # raises: restore without having saved # after mob.save_state() mob.shift(RIGHT * 2) self.play(Restore(mob))
Defensive patterns
Strategy: validation
Validate before calling
if getattr(mob, 'saved_state', None) is None:
mob.save_state()
mob.restore() Prevention
- Always pair save_state() with restore()/Restore() in the same function
- Treat Restore animations as invalid unless save_state appears earlier in the scene
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Mobject cannot contain self
- Cannot position endpoints of closed loop
- Need at least one color
- Cannot call Mobject.{} for a Mobject with no points
- Method chaining is currently not supported for overridden an
AI-assisted analysis of 3b1b/manim@dee01804d4 (2026-08-14).
Data as JSON: /api/errors/020f82719579a309.
Report an issue: GitHub.