3b1b/manim · error · Exception

Lines do not intersect

Error message

Lines do not intersect

What it means

Raised by line_intersection (utils/space_ops.py:286) when the determinant of the direction differences (div) is zero, i.e. the two lines are parallel (or collinear) so there is no unique intersection point. The 2D cross-product formulation degenerates and the function refuses to divide by zero.

Source

Thrown at manimlib/utils/space_ops.py:286

def line_intersection(
    line1: Tuple[Vect3, Vect3],
    line2: Tuple[Vect3, Vect3]
) -> Vect3:
    """
    return intersection point of two lines,
    each defined with a pair of vectors determining
    the end points
    """
    x_diff = (line1[0][0] - line1[1][0], line2[0][0] - line2[1][0])
    y_diff = (line1[0][1] - line1[1][1], line2[0][1] - line2[1][1])

    def det(a, b):
        return a[0] * b[1] - a[1] * b[0]

    div = det(x_diff, y_diff)
    if div == 0:
        raise Exception("Lines do not intersect")
    d = (det(*line1), det(*line2))
    x = det(d, x_diff) / div
    y = det(d, y_diff) / div
    return np.array([x, y, 0])


def find_intersection(
    p0: Vect3 | Vect3Array,
    v0: Vect3 | Vect3Array,
    p1: Vect3 | Vect3Array,
    v1: Vect3 | Vect3Array,
    threshold: float = 1e-5,
) -> Vect3:
    """
    Return the intersection of a line passing through p0 in direction v0
    with one passing through p1 in direction v1.  (Or array of intersections
    from arrays of such points/directions).

View on GitHub (pinned to dee01804d4)

Solutions

  1. Check direction vectors first: if np.cross(v0, v1) == 0 (or below a tolerance), handle the parallel case explicitly instead of calling line_intersection
  2. Nudge one line's direction by a tiny epsilon only if approximate behavior is acceptable
  3. Prefer find_intersection(p0, v0, p1, v1) which handles 3D/segment cases with a threshold, when appropriate to your inputs

Example fix

# before
pt = line_intersection([a, b], [c, d])  # parallel -> raises

# after
v0, v1 = b - a, d - c
if abs(v0[0] * v1[1] - v0[1] * v1[0]) < 1e-9:
    pt = None  # parallel: no intersection
else:
    pt = line_intersection([a, b], [c, d])
Defensive patterns

Strategy: validation

Validate before calling

def lines_intersect(l1, l2, tol=1e-9) -> bool:
    d0 = (l1[1][0] - l1[0][0], l1[1][1] - l1[0][1])
    d1 = (l2[1][0] - l2[0][0], l2[1][1] - l2[0][1])
    return abs(d0[0] * d1[1] - d0[1] * d1[0]) > tol

Try / catch

try:
    pt = line_intersection(l1, l2)
except Exception:
    pt = None  # parallel or collinear lines

Prevention

When it happens

Trigger: line_intersection([p0, p0 + RIGHT], [p1, p1 + RIGHT]) with two horizontal lines; two segments sharing the same direction vector; numerically near-parallel lines where floating point rounds div to exactly 0.0.

Common situations: Computing intersections of grid lines or axes-aligned edges; geometry code assuming lines always cross; animations placing labels at line crossings that happen to be parallel in edge cases.

Related errors


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