{"record":{"id":"e698ab5888bb4639","repo":"3b1b/manim","slug":"at-least-2-mobjects-needed-for-exclusion","errorCode":null,"errorMessage":"At least 2 mobjects needed for Exclusion.","messagePattern":"At least 2 mobjects needed for Exclusion\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"manimlib/mobject/boolean_ops.py","lineNumber":104,"sourceCode":"            [_convert_vmobject_to_skia_path(vmobjects[1])],\r\n            outpen.getPen(),\r\n        )\r\n        new_outpen = outpen\r\n        for _i in range(2, len(vmobjects)):\r\n            new_outpen = pathops.Path()\r\n            pathops.intersection(\r\n                [outpen],\r\n                [_convert_vmobject_to_skia_path(vmobjects[_i])],\r\n                new_outpen.getPen(),\r\n            )\r\n            outpen = new_outpen\r\n        _convert_skia_path_to_vmobject(outpen, self)\r\n\r\n\r\nclass Exclusion(VMobject):\r\n    def __init__(self, *vmobjects: VMobject, **kwargs):\r\n        if len(vmobjects) < 2:\r\n            raise ValueError(\"At least 2 mobjects needed for Exclusion.\")\r\n        super().__init__(**kwargs)\r\n        outpen = pathops.Path()\r\n        pathops.xor(\r\n            [_convert_vmobject_to_skia_path(vmobjects[0])],\r\n            [_convert_vmobject_to_skia_path(vmobjects[1])],\r\n            outpen.getPen(),\r\n        )\r\n        new_outpen = outpen\r\n        for _i in range(2, len(vmobjects)):\r\n            new_outpen = pathops.Path()\r\n            pathops.xor(\r\n                [outpen],\r\n                [_convert_vmobject_to_skia_path(vmobjects[_i])],\r\n                new_outpen.getPen(),\r\n            )\r\n            outpen = new_outpen\r\n        _convert_skia_path_to_vmobject(outpen, self)\r\n","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/3b1b/manim/blob/dee01804d47b9f94402d71472674710dcac125b8/manimlib/mobject/boolean_ops.py#L86-L122","documentation":"ValueError raised in Exclusion.__init__ (manimlib/mobject/boolean_ops.py:104). Exclusion computes pairwise XOR via pathops.xor starting with vmobjects[0] and vmobjects[1], so at least two operands are required; the guard fires before any geometry work.","triggerScenarios":"Exclusion(one_mob), Exclusion(), or Exclusion(*mobs) where mobs contains fewer than two mobjects after programmatic filtering.","commonSituations":"Dynamic operand lists; user-config-driven scene building where an operand list degenerates to one element; refactors that removed an operand.","solutions":["Pass at least two VMobjects: Exclusion(mob_a, mob_b)","Validate collection length before splatting","Use mob.copy() semantics if only one shape was intended"],"exampleFix":"# before\nxor_shape = Exclusion(*mobs)  # raises when len(mobs) < 2\n\n# after\nif len(mobs) >= 2:\n    xor_shape = Exclusion(*mobs)\nelse:\n    raise SystemExit(f\"Need >=2 mobjects, got {len(mobs)}\")","handlingStrategy":"validation","validationCode":"if len(mobs) >= 2:\n    xor_shape = Exclusion(*mobs)\nelse:\n    raise ValueError(f\"Exclusion needs >= 2 mobjects, got {len(mobs)}\")","typeGuard":"def is_exclusion_ready(mobs: list) -> bool:\n    return len(mobs) >= 2","tryCatchPattern":null,"preventionTips":["Count operands before Exclusion(*mobs)","Treat a one-element operand list as a config bug, not a special case to silence"],"tags":["manim","boolean-ops","validation"],"backgroundTag":null,"analyzedSha":"dee01804d47b9f94402d71472674710dcac125b8","analyzedAt":"2026-08-14T19:53:44.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}