{"record":{"id":"682d380e12b46bfe","repo":"3b1b/manim","slug":"functions-passed-to-applyfunction-must-return-obje","errorCode":null,"errorMessage":"Functions passed to ApplyFunction must return object of type Mobject","messagePattern":"Functions passed to ApplyFunction must return object of type Mobject","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"manimlib/animation/transform.py","lineNumber":263,"sourceCode":"        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\n\n\nclass ApplyMatrix(ApplyPointwiseFunction):\n    def __init__(\n        self,\n        matrix: npt.ArrayLike,\n        mobject: Mobject,\n        **kwargs\n    ):\n        matrix = self.initialize_matrix(matrix)\n\n        def func(p):\n            return np.dot(p, matrix.T)\n\n        super().__init__(func, mobject, **kwargs)\n\n    def initialize_matrix(self, matrix: npt.ArrayLike) -> np.ndarray:","sourceCodeStart":245,"sourceCodeEnd":281,"githubUrl":"https://github.com/3b1b/manim/blob/dee01804d47b9f94402d71472674710dcac125b8/manimlib/animation/transform.py#L245-L281","documentation":"ApplyFunction creates its target by running the user-supplied function on a copy of the mobject; create_target verifies the return value is a Mobject. Functions that return None (mutating in place without returning) or any non-Mobject trigger the Exception.","triggerScenarios":"ApplyFunction(lambda m: m.scale(2), mob) works only because mobject methods return self; a lambda like lambda m: m.scale(2) and None or a function whose last statement is a non-returning call fails; returning a tuple (mobject, value) also fails.","commonSituations":"Writing a function that mutates the mobject but forgets to return it — very easy with lambdas whose body is a statement-like call; functions adapted from scene code that never needed a return value.","solutions":["Make the function return the mobject: def f(m): m.scale(2); m.set_color(RED); return m","For lambdas, chain method calls since each returns the mobject: lambda m: m.scale(2).set_color(RED)","If you only need pointwise mapping, use ApplyPointwiseFunction instead"],"exampleFix":"# before\nself.play(ApplyFunction(lambda m: m.scale(2).set_color(RED), mob))  # if a branch returns None\n# after\ndef grow(m):\n    m.scale(2).set_color(RED)\n    return m\nself.play(ApplyFunction(grow, mob))","handlingStrategy":"validation","validationCode":"def apply_and_return(m):\n    result = my_func(m)\n    assert isinstance(result, Mobject), \"function must return a Mobject\"\n    return result\nself.play(ApplyFunction(apply_and_return, mob))","typeGuard":"def returns_mobject(fn, sample: Mobject) -> bool:\n    return isinstance(fn(sample.copy()), Mobject)","tryCatchPattern":null,"preventionTips":["End every function passed to ApplyFunction with an explicit `return m`","Avoid multi-statement lambdas emulated with `and` — a None-returning branch slips in silently"],"tags":["animation","transform","api-misuse","validation"],"backgroundTag":null,"analyzedSha":"dee01804d47b9f94402d71472674710dcac125b8","analyzedAt":"2026-08-14T19:53:44.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}