3b1b/manim · error · Exception

MoveToTarget called on mobject without attribute 'target'

Error message

MoveToTarget called on mobject without attribute 'target'

What it means

MoveToTarget animates a mobject toward its pre-generated .target copy. The mobject.target attribute is created only by Mobject.generate_target(); MoveToTarget.check_validity_of_input raises immediately in the constructor if it is absent.

Source

Thrown at manimlib/animation/transform.py:145

class ReplacementTransform(Transform):
    replace_mobject_with_target_in_scene: bool = True


class TransformFromCopy(Transform):
    replace_mobject_with_target_in_scene: bool = True

    def __init__(self, mobject: Mobject, target_mobject: Mobject, **kwargs):
        super().__init__(mobject.copy(), target_mobject, **kwargs)


class MoveToTarget(Transform):
    def __init__(self, mobject: Mobject, **kwargs):
        self.check_validity_of_input(mobject)
        super().__init__(mobject, mobject.target, **kwargs)

    def check_validity_of_input(self, mobject: Mobject) -> None:
        if not hasattr(mobject, "target"):
            raise Exception(
                "MoveToTarget called on mobject without attribute 'target'"
            )


class _MethodAnimation(MoveToTarget):
    def __init__(self, mobject: Mobject, methods: list[Callable], **kwargs):
        self.methods = methods
        super().__init__(mobject, **kwargs)


class ApplyMethod(Transform):
    def __init__(self, method: Callable, *args, **kwargs):
        """
        method is a method of Mobject, *args are arguments for
        that method.  Key word arguments should be passed in
        as the last arg, as a dict, since **kwargs is for
        configuration of the transform itself

View on GitHub (pinned to dee01804d4)

Solutions

  1. Call mobject.generate_target() first, mutate mobject.target, then self.play(MoveToTarget(mobject))
  2. If you don't need the two-step idiom, use Transform(mob, mob.copy().shift(RIGHT)) or mob.animate.shift(RIGHT) instead

Example fix

# before
self.play(MoveToTarget(circle))
# after
circle.generate_target()
circle.target.scale(2)
self.play(MoveToTarget(circle))
Defensive patterns

Strategy: validation

Validate before calling

if not hasattr(mobject, "target") or mobject.target is None:
    mobject.generate_target()
mobject.target.shift(RIGHT)
self.play(MoveToTarget(mobject))

Type guard

def has_target(mobject) -> bool:
    return getattr(mobject, "target", None) is not None

Prevention

When it happens

Trigger: Playing MoveToTarget(mob) without a preceding mob.generate_target(); or calling mob.generate_target() on a different mobject than the one passed to MoveToTarget.

Common situations: Classic manim idiom is mob.generate_target(); mob.target.shift(RIGHT); self.play(MoveToTarget(mob)) — forgetting the first line is by far the most common hit; also after re-creating the mobject variable the .target is lost.

Related errors


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