{"record":{"id":"e59f6519ef70c452","repo":"3b1b/manim","slug":"method-chaining-is-currently-not-supported-for-ove","errorCode":null,"errorMessage":"Method chaining is currently not supported for overridden animations","messagePattern":"Method chaining is currently not supported for overridden animations","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"manimlib/mobject/mobject.py","lineNumber":2157,"sourceCode":"\n\nclass _AnimationBuilder:\n    def __init__(self, mobject: Mobject):\n        self.mobject = mobject\n        self.overridden_animation = None\n        self.mobject.generate_target()\n        self.is_chaining = False\n        self.methods: list[Callable] = []\n        self.anim_args = {}\n        self.can_pass_args = True\n\n    def __getattr__(self, method_name: str):\n        method = getattr(self.mobject.target, method_name)\n        self.methods.append(method)\n        has_overridden_animation = hasattr(method, \"_override_animate\")\n\n        if (self.is_chaining and has_overridden_animation) or self.overridden_animation:\n            raise NotImplementedError(\n                \"Method chaining is currently not supported for \" + \\\n                \"overridden animations\"\n            )\n\n        def update_target(*method_args, **method_kwargs):\n            if has_overridden_animation:\n                self.overridden_animation = method._override_animate(\n                    self.mobject, *method_args, **method_kwargs\n                )\n            else:\n                method(*method_args, **method_kwargs)\n            return self\n\n        self.is_chaining = True\n        return update_target\n\n    def __call__(self, **kwargs):\n        return self.set_anim_args(**kwargs)","sourceCodeStart":2139,"sourceCodeEnd":2175,"githubUrl":"https://github.com/3b1b/manim/blob/dee01804d47b9f94402d71472674710dcac125b8/manimlib/mobject/mobject.py#L2139-L2175","documentation":"NotImplementedError from _AnimBuilder.__getattr__ (manimlib/mobject/mobject.py:2157). The animate syntax builds a chain of method calls; some methods (e.g. certain VMobject/geometry methods) carry an _override_animate marker that swaps in a custom animation. Chaining further calls while such an overridden animation is already pending (or chaining after one within the same builder) is not supported by the builder's implementation, so it raises instead of producing a wrong animation.","triggerScenarios":"mob.animate.some_overridden_method(...).shift(...) where some_overridden_method has an _override_animate attribute (methods wrapped via the override_animate decorator at mobject.py:2224); chaining two overridden-animation methods: mob.animate.a(...).b(...) where both are overridden; using is_chaining with an overridden method.","commonSituations":"Long fluent chains in scene code like circle.animate.move_to(x).set_fill(...).scale(2) where one link happens to be an animate-overridden method; library versions that add more _override_animate decorated methods, breaking previously working chains.","solutions":["Split the chain: play the overridden-animation call first, then chain the rest in a separate animate expression (self.play(mob.animate.a(...)) then self.play(mob.animate.shift(...)))","Reorder so the overridden method is the LAST call in the chain","Replace the overridden call with its non-animated equivalent wrapped in a Transform/ApplyMethod if chaining is essential"],"exampleFix":"# before\nself.play(mob.animate.move_to(ORIGIN).shift(RIGHT))\n# if move_to had an _override_animate in your version -> NotImplementedError\n\n# after\nself.play(mob.animate.move_to(ORIGIN))\nself.play(mob.animate.shift(RIGHT))","handlingStrategy":"fallback","validationCode":null,"typeGuard":"def has_override_animate(method) -> bool:\n    return hasattr(method, \"_override_animate\")\n\n# check before chaining:\n# method = getattr(mob, name)\n# if has_override_animate(method): keep it last / play it alone","tryCatchPattern":"try:\n    builder = mob.animate.move_to(p).shift(RIGHT)\nexcept NotImplementedError:\n    builder = mob.animate.shift(RIGHT)  # play overridden call separately","preventionTips":["Keep overridden-animation methods as the last call in an animate chain, or play them alone","Split long chains into multiple self.play calls when in doubt","Check for the _override_animate attribute when writing generic animation wrappers"],"tags":["manim","animate-syntax","animation","api-limitation"],"backgroundTag":null,"analyzedSha":"dee01804d47b9f94402d71472674710dcac125b8","analyzedAt":"2026-08-14T19:53:44.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}