matplotlib/matplotlib · error · ValueError

Got unknown shape: {self._shape!r}

Error message

Got unknown shape: {self._shape!r}

What it means

patches.FancyArrow(x, y, dx, dy, ...) draws the shaft plus head halves selected by its shape parameter, which may only be 'full', 'left', or 'right'. _get_path's geometry code falls through to raise ValueError(f"Got unknown shape: {self._shape!r}") for any other value, at construction/draw time.

Source

Thrown at lib/matplotlib/patches.py:1633

                left_half_arrow += [head_length, 0]
            # if the head starts at 0, shift up by another head length
            if self._head_starts_at_zero:
                left_half_arrow += [head_length / 2, 0]
            # figure out the shape, and complete accordingly
            if self._shape == 'left':
                coords = left_half_arrow
            else:
                right_half_arrow = left_half_arrow * [1, -1]
                if self._shape == 'right':
                    coords = right_half_arrow
                elif self._shape == 'full':
                    # The half-arrows contain the midpoint of the stem,
                    # which we can omit from the full arrow. Including it
                    # twice caused a problem with xpdf.
                    coords = np.concatenate([left_half_arrow[:-1],
                                             right_half_arrow[-2::-1]])
                else:
                    raise ValueError(f"Got unknown shape: {self._shape!r}")
            if distance != 0:
                cx = self._dx / distance
                sx = self._dy / distance
            else:
                # Account for division by zero
                cx, sx = 0, 1
            M = [[cx, sx], [-sx, cx]]
            self.verts = np.dot(coords, M) + [
                self._x + self._dx,
                self._y + self._dy,
            ]


_docstring.interpd.register(
    FancyArrow="\n".join(
        (inspect.getdoc(FancyArrow.__init__) or "").splitlines()[2:]))

View on GitHub (pinned to b379c1b69e)

Solutions

  1. Use one of 'full' (default), 'left', or 'right'.
  2. Validate free-form input against the allowed set before constructing.
  3. For richer head styles (open heads, filled variants, mutation_scale), switch to FancyArrowPatch with arrowstyle, or ax.annotate.
  4. Check for typos — this is the most common single cause.

Example fix

# before
arrow = patches.FancyArrow(0, 0, 1, 0.5, width=0.05, shape='both')

# after
arrow = patches.FancyArrow(0, 0, 1, 0.5, width=0.05, shape='full')
# or richer styling: patches.FancyArrowPatch((0, 0), (1, 0.5), arrowstyle='<|-|>', mutation_scale=15)
Defensive patterns

Strategy: validation

Validate before calling

shape = shape if shape in ('full', 'left', 'right') else 'full'
arrow = patches.FancyArrow(x, y, dx, dy, shape=shape)

Type guard

def is_valid_arrow_shape(s) -> bool:
    return s in ('full', 'left', 'right')

Prevention

When it happens

Trigger: FancyArrow(0, 0, 1, 1, shape='both') or shape='halves'; typos like shape='ful'; passing head-orientation strings from other APIs (e.g. '<|-|>' annotation styles); passing None.

Common situations: Confusing FancyArrow's shape with annotate/FancyArrowPatch arrowstyle strings; exposing a user 'arrow head side' option without validation; copy-pasting from examples using different libraries (plotly's 'head' vocabulary).

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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