3b1b/manim · error · ValueError

At least 2 mobjects needed for Union.

Error message

At least 2 mobjects needed for Union.

What it means

ValueError raised in Union.__init__ (manimlib/mobject/boolean_ops.py:55). Union implements boolean union via skia-pathops, which requires at least two input paths to compute a meaningful result. Passing fewer than two VMobjects (zero or one) is rejected before any path conversion happens.

Source

Thrown at manimlib/mobject/boolean_ops.py:55

            if path_verb == PathVerb.MOVE:
                for point in points:
                    current_path_start = point
                    vmobject.start_new_path(point)
            elif path_verb == PathVerb.CUBIC:
                vmobject.add_cubic_bezier_curve_to(*points)
            elif path_verb == PathVerb.LINE:
                vmobject.add_line_to(points[0])
            elif path_verb == PathVerb.QUAD:
                vmobject.add_quadratic_bezier_curve_to(*points)
            else:
                raise Exception(f"Unsupported: {path_verb}")
    return vmobject.reverse_points()


class Union(VMobject):
    def __init__(self, *vmobjects: VMobject, **kwargs):
        if len(vmobjects) < 2:
            raise ValueError("At least 2 mobjects needed for Union.")
        super().__init__(**kwargs)
        outpen = pathops.Path()
        paths = [
            _convert_vmobject_to_skia_path(vmobject)
            for vmobject in vmobjects
        ]
        pathops.union(paths, outpen.getPen())
        _convert_skia_path_to_vmobject(outpen, self)


class Difference(VMobject):
    def __init__(self, subject: VMobject, clip: VMobject, **kwargs):
        super().__init__(**kwargs)
        outpen = pathops.Path()
        pathops.difference(
            [_convert_vmobject_to_skia_path(subject)],
            [_convert_vmobject_to_skia_path(clip)],
            outpen.getPen(),

View on GitHub (pinned to dee01804d4)

Solutions

  1. Pass at least two VMobjects: Union(mob_a, mob_b)
  2. Guard dynamic calls: if len(mobs) < 2: skip or return mobs[0]
  3. If you meant a copy/transform of one shape, use mob.copy() or mob.replicate() instead of Union

Example fix

# before
result = Union(*shapes)  # raises when len(shapes) < 2

# after
result = shapes[0] if len(shapes) == 1 else (Union(*shapes) if len(shapes) >= 2 else None)
Defensive patterns

Strategy: validation

Validate before calling

def safe_union(*mobs):
    assert len(mobs) >= 2, "Union requires at least 2 mobjects"
    return Union(*mobs)

Type guard

from manimlib.mobject.types.vectorized_mobject import VMobject

def is_union_ready(mobs: list) -> bool:
    return len(mobs) >= 2 and all(isinstance(m, VMobject) for m in mobs)

Prevention

When it happens

Trigger: Union(single_mob), Union() with no arguments, or Union(*list_of_mobjects) where the list has been emptied by earlier filtering logic.

Common situations: Programmatic code that does Union(*mobs) over a dynamically-built list; refactoring that accidentally drops an operand; looping over pairs where an off-by-one leaves one element.

Related errors


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