{"record":{"id":"843bb8bae09d0390","repo":"matplotlib/matplotlib","slug":"no-renderer-defined-843bb8","errorCode":null,"errorMessage":"No renderer defined","messagePattern":"No renderer defined","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"lib/matplotlib/table.py","lineNumber":412,"sourceCode":"    @edges.setter\n    def edges(self, value):\n        self._edges = value\n        self.stale = True\n\n    def _approx_text_height(self):\n        return (self.FONTSIZE / 72.0 * self.get_figure(root=True).dpi /\n                self._axes.bbox.height * 1.2)\n\n    @allow_rasterization\n    def draw(self, renderer):\n        # docstring inherited\n\n        # Need a renderer to do hit tests on mouseevent; assume the last one\n        # will do\n        if renderer is None:\n            renderer = self.get_figure(root=True)._get_renderer()\n        if renderer is None:\n            raise RuntimeError('No renderer defined')\n\n        if not self.get_visible():\n            return\n        renderer.open_group('table', gid=self.get_gid())\n        self._update_positions(renderer)\n\n        for key in sorted(self._cells):\n            self._cells[key].draw(renderer)\n\n        renderer.close_group('table')\n        self.stale = False\n\n    def _get_grid_bbox(self, renderer):\n        \"\"\"\n        Get a bbox, in axes coordinates for the cells.\n\n        Only include those in the range (0, 0) to (maxRow, maxCol).\n        \"\"\"","sourceCodeStart":394,"sourceCodeEnd":430,"githubUrl":"https://github.com/matplotlib/matplotlib/blob/b379c1b69e012b142c0f496a52bcb30513802d72/lib/matplotlib/table.py#L394-L430","documentation":"Table.draw needs a renderer both to paint and for its internal hit-test bookkeeping. If the renderer argument is None it falls back to the root figure's cached renderer, and if that is also None it raises RuntimeError('No renderer defined') (table.py:412). This only happens outside the normal draw flow — a Figure that was never attached to a canvas, or a manual tab.draw(None) call.","triggerScenarios":"fig = matplotlib.figure.Figure() (no canvas); ax.table(...) then tab.draw(None) by hand; custom backends or embedded code invoking Artist.draw directly before any canvas draw; test harnesses that build figures without a backend canvas.","commonSituations":"Unit tests instantiating bare Figure objects; scripts run headless without selecting a backend; embedding code copied from tutorials that call draw() at the wrong lifecycle point.","solutions":["Attach a canvas: from matplotlib.backends.backend_agg import FigureCanvasAgg; FigureCanvasAgg(fig) — then trigger fig.canvas.draw() instead of calling table.draw yourself","If you must call draw directly, pass a renderer: tab.draw(fig.canvas.get_renderer())","Prefer fig.savefig(...) or fig.canvas.draw_idle(), which obtain renderers through the canvas"],"exampleFix":"# before: bare Figure, no canvas\nfrom matplotlib.figure import Figure\nfig = Figure()\nax = fig.add_subplot()\ntab = ax.table(cellText=[['x']])\ntab.draw(None)  # RuntimeError: No renderer defined\n\n# after: attach an Agg canvas and draw through it\nfrom matplotlib.backends.backend_agg import FigureCanvasAgg\nfig = Figure()\nFigureCanvasAgg(fig)\nax = fig.add_subplot()\ntab = ax.table(cellText=[['x']])\nfig.canvas.draw()","handlingStrategy":"try-catch","validationCode":"def table_drawable(fig) -> bool:\n    canvas = fig.canvas\n    return canvas is not None and hasattr(canvas, 'get_renderer')\n\nif not table_drawable(fig):\n    from matplotlib.backends.backend_agg import FigureCanvasAgg\n    FigureCanvasAgg(fig)","typeGuard":null,"tryCatchPattern":"try:\n    fig.canvas.draw()\nexcept RuntimeError as e:\n    if 'No renderer defined' in str(e):\n        from matplotlib.backends.backend_agg import FigureCanvasAgg\n        FigureCanvasAgg(fig)   # attach a canvas, then retry once\n        fig.canvas.draw()\n    else:\n        raise","preventionTips":["Never call Artist.draw directly; drive rendering through fig.canvas.draw() or fig.savefig()","In tests, always pair Figure() with FigureCanvasAgg(fig) before drawing","Embedding code should obtain renderers via fig.canvas.get_renderer(), not cache stale ones"],"tags":["matplotlib","table","runtimeerror","renderer","headless","canvas"],"backgroundTag":"renderer-unavailable","analyzedSha":"b379c1b69e012b142c0f496a52bcb30513802d72","analyzedAt":"2026-08-21T23:31:55.468Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}