{"record":{"id":"2111628bd231d464","repo":"3b1b/manim","slug":"mobject-cannot-contain-self","errorCode":null,"errorMessage":"Mobject cannot contain self","messagePattern":"Mobject cannot contain self","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"manimlib/mobject/mobject.py","lineNumber":433,"sourceCode":"        If extended is set to true, it includes the ancestors of all family members,\n        e.g. any other parents of a submobject\n        \"\"\"\n        ancestors = []\n        to_process = list(self.get_family(recurse=extended))\n        excluded = set(to_process)\n        while to_process:\n            for p in to_process.pop().parents:\n                if p not in excluded:\n                    ancestors.append(p)\n                    to_process.append(p)\n        # Ensure mobjects highest in the hierarchy show up first\n        ancestors.reverse()\n        # Remove list redundancies while preserving order\n        return list(dict.fromkeys(ancestors))\n\n    def add(self, *mobjects: Mobject) -> Self:\n        if self in mobjects:\n            raise Exception(\"Mobject cannot contain self\")\n        for mobject in mobjects:\n            if mobject not in self.submobjects:\n                self.submobjects.append(mobject)\n            if self not in mobject.parents:\n                mobject.parents.append(self)\n        self.note_changed_family()\n        return self\n\n    def remove(\n        self,\n        *to_remove: Mobject,\n        reassemble: bool = True,\n        recurse: bool = True\n    ) -> Self:\n        for parent in self.get_family(recurse):\n            for child in to_remove:\n                if child in parent.submobjects:\n                    parent.submobjects.remove(child)","sourceCodeStart":415,"sourceCodeEnd":451,"githubUrl":"https://github.com/3b1b/manim/blob/dee01804d47b9f94402d71472674710dcac125b8/manimlib/mobject/mobject.py#L415-L451","documentation":"Exception('Mobject cannot contain self') raised by Mobject.add (manimlib/mobject/mobject.py:433). A mobject's family is a tree; adding a mobject to itself would create a cycle and corrupt family traversal (get_family, note_changed_family), so manim rejects mob.add(mob) explicitly before touching submobjects.","triggerScenarios":"Calling mob.add(mob); passing the same object into its own constructor pattern like vg.add(vg); dynamic code where a group is built from a list that accidentally already contains the group being filled.","commonSituations":"Accumulating results in-place: group = VGroup(); for x in items: group.add(group) style bugs; splatting a container into itself: group.add(*group) is fine (children, not self), but group.add(group) is not; copy/paste of add boilerplate.","solutions":["Remove the self-referential add: audit callsites for mob.add(mob) or VGroup construction including the group itself","When merging groups, add the OTHER group's submobjects: a.add(*b) or use VGroup(a, b)","Use group.add(*others) only with objects distinct from group"],"exampleFix":"# before\ngroup = VGroup()\nfor shape in shapes:\n    group.add(group, shape)  # raises: cannot contain self\n\n# after\ngroup = VGroup()\nfor shape in shapes:\n    group.add(shape)","handlingStrategy":"validation","validationCode":"def safe_add(group, *mobs):\n    for m in mobs:\n        assert m is not group, \"cannot add a group to itself\"\n    group.add(*mobs)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never pass the container itself into its own add()","Build new containers instead of mutating one from a list that includes it"],"tags":["manim","mobject","scene-graph","validation"],"backgroundTag":null,"analyzedSha":"dee01804d47b9f94402d71472674710dcac125b8","analyzedAt":"2026-08-14T19:53:44.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}