matplotlib/matplotlib · error · ValueError

'head_width' must be nonnegative

Error message

'head_width' must be nonnegative

What it means

The 'rarrow' box style (BoxStyle.RArrow, used by FancyBboxPatch) draws a right-pointing arrow whose head width is head_width times the shaft width. A negative head width would produce inverted, invalid geometry, so the constructor rejects head_width < 0 immediately. Zero is allowed and yields a headless flat right edge.

Source

Thrown at lib/matplotlib/patches.py:2585

        """A box in the shape of a right-pointing arrow."""

        def __init__(self, pad=0.3, head_width=1.5, head_angle=90):
            """
            Parameters
            ----------
            pad : float, default: 0.3
                The amount of padding around the original box.
            head_width : float, default: 1.5
                The head width, relative to the arrow shaft width; must be
                nonnegative.
            head_angle : float, default: 90
                The angle at the tip of the arrow, in degrees; must be nonzero
                (modulo 360).  Negative angles result in arrow heads pointing
                backwards.
            """
            self.pad = pad
            if head_width < 0:
                raise ValueError("'head_width' must be nonnegative")
            self.head_width = head_width
            if head_angle % 360 == 0:
                raise ValueError("'head_angle' must be nonzero")
            self.head_angle = head_angle

        def __call__(self, x0, y0, width, height, mutation_size):
            # padding & padded dimensions
            pad = mutation_size * self.pad
            dx, dy = width + 2 * pad, height + 2 * pad
            x0, y0 = x0 - pad, y0 - pad,
            x1, y1 = x0 + dx, y0 + dy

            head_dy = self.head_width * dy
            mid_y = (y0 + y1) / 2
            shaft_y0 = mid_y - head_dy / 2
            shaft_y1 = mid_y + head_dy / 2

            cot = 1 / math.tan(math.radians(self.head_angle / 2))

View on GitHub (pinned to b379c1b69e)

Solutions

  1. Use a nonnegative value; the default is 1.5 (relative to the arrow shaft width)
  2. Clamp config input: head_width=abs(float(cfg.get('head_width', 1.5)))
  3. Use head_width=0 if you want the arrow shape without a widened head

Example fix

// before
box = FancyBboxPatch((0, 0), 1, 1, boxstyle=f'rarrow,head_width={w}')  # w = -0.5
// after
box = FancyBboxPatch((0, 0), 1, 1, boxstyle=f'rarrow,head_width={abs(w)}')
Defensive patterns

Strategy: validation

Validate before calling

head_width = float(cfg.get('head_width', 1.5))
if head_width < 0:
    head_width = abs(head_width)  # or raise for strict config validation
box = FancyBboxPatch((0, 0), 1, 1, boxstyle='rarrow', head_width=head_width)

Prevention

When it happens

Trigger: BoxStyle.RArrow(head_width=-1); FancyBboxPatch(boxstyle='rarrow,head_width=-0.5'); a config-driven head_width whose sign is computed (e.g. head_width=-w instead of abs(w)).

Common situations: Sign errors from arithmetic on user config; parsing a value with a stray minus from a config file or CLI; unit-test fixtures sweeping negative values.

Related errors


AI-assisted analysis of matplotlib/matplotlib@b379c1b69e (2026-08-21). Data as JSON: /api/errors/422316aea12013d5. Report an issue: GitHub.