matplotlib/matplotlib · error · RuntimeError

Cannot get window extent of text w/o renderer. You likely wa

Error message

Cannot get window extent of text w/o renderer. You likely want to call 'figure.draw_without_rendering()' first.

What it means

Text.get_window_extent() (lib/matplotlib/text.py) needs a renderer to measure glyph sizes. If the caller passes none, it tries the renderer stored on the Text and then the figure's fig._get_renderer(); when both are None (typically a figure whose canvas cannot supply a renderer before any draw), this RuntimeError is raised with the recommended fix in the message: call figure.draw_without_rendering() first.

Source

Thrown at lib/matplotlib/text.py:1071

            e.g. if to match regions with a figure saved with a custom dpi value.
        """
        if not self.get_visible():
            return Bbox.unit()

        fig = self.get_figure(root=True)
        if dpi is None:
            dpi = fig.dpi
        if self.get_text() == '':
            with cbook._setattr_cm(fig, dpi=dpi):
                tx, ty = self._get_xy_display()
                return Bbox.from_bounds(tx, ty, 0, 0)

        if renderer is not None:
            self._renderer = renderer
        if self._renderer is None:
            self._renderer = fig._get_renderer()
        if self._renderer is None:
            raise RuntimeError(
                "Cannot get window extent of text w/o renderer. You likely "
                "want to call 'figure.draw_without_rendering()' first.")

        with cbook._setattr_cm(fig, dpi=dpi):
            bbox, _, _ = self._get_layout(self._renderer)
            x, y = self.get_unitless_position()
            x, y = self.get_transform().transform((x, y))
            bbox = bbox.translated(x, y)
            return bbox

    def get_tightbbox(self, renderer=None):
        if not self.get_visible() or self.get_text() == "":
            return Bbox.null()
        # Exclude text at data coordinates outside the valid domain of the axes
        # scales (e.g., negative coordinates with a log scale).
        if (self.axes
                and self.get_transform() == self.axes.transData
                and not self.axes._point_in_data_domain(*self.get_unitless_position())):

View on GitHub (pinned to b379c1b69e)

Solutions

  1. Call fig.draw_without_rendering() once before measuring, as the message suggests - this initializes a renderer without producing an image file.
  2. Or pass the renderer explicitly: t.get_window_extent(fig.canvas.get_renderer()) on Agg-based backends.
  3. Or trigger a real draw first (fig.canvas.draw()) if you are rendering anyway.
  4. For savefig-only workflows, use bbox_inches='tight' and let matplotlib handle measurement.

Example fix

# before
fig, ax = plt.subplots()
t = ax.set_title('measure me')
bbox = t.get_window_extent()  # RuntimeError: no renderer

# after
fig.draw_without_rendering()
bbox = t.get_window_extent()
Defensive patterns

Strategy: validation

Validate before calling

# ensure a renderer exists before measuring any Text
fig.draw_without_rendering()
# or explicitly:
renderer = fig.canvas.get_renderer()  # Agg-style backends
bbox = text_obj.get_window_extent(renderer)

Prevention

When it happens

Trigger: text.get_window_extent() with no argument on a figure that has never been drawn; measuring text on a canvas that does not provide a renderer until draw (some non-GUI or partially initialized backends); code that previously passed a renderer but now runs headless; empty-string shortcuts do not hit this - any non-empty text does.

Common situations: Computing label bboxes to size a figure before saving (savefig with bbox_inches='tight' does this for you); headless report-generation pipelines that call get_window_extent on fresh figures; upgrading code from older matplotlib where a stale self._renderer happened to survive.

Related errors


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