{"record":{"id":"1daf64a67179761e","repo":"matplotlib/matplotlib","slug":"invalid-image-format-r-in-plot-formats","errorCode":null,"errorMessage":"invalid image format \"%r\" in plot_formats","messagePattern":"invalid image format \"%r\" in plot_formats","errorType":"exception","errorClass":"PlotError","httpStatus":null,"severity":"error","filePath":"lib/matplotlib/sphinxext/plot_directive.py","lineNumber":636,"sourceCode":"    matplotlib.rc_file_defaults()\n    matplotlib.rcParams.update(plot_rcparams)\n\n\ndef get_plot_formats(config):\n    default_dpi = {'png': 80, 'hires.png': 200, 'pdf': 200}\n    formats = []\n    plot_formats = config.plot_formats\n    for fmt in plot_formats:\n        if isinstance(fmt, str):\n            if ':' in fmt:\n                suffix, dpi = fmt.split(':')\n                formats.append((str(suffix), int(dpi)))\n            else:\n                formats.append((fmt, default_dpi.get(fmt, 80)))\n        elif isinstance(fmt, (tuple, list)) and len(fmt) == 2:\n            formats.append((str(fmt[0]), int(fmt[1])))\n        else:\n            raise PlotError('invalid image format \"%r\" in plot_formats' % fmt)\n    return formats\n\n\ndef _parse_srcset(entries):\n    \"\"\"\n    Parse srcset for multiples...\n    \"\"\"\n    srcset = {}\n    for entry in entries:\n        entry = entry.strip()\n        if len(entry) >= 2:\n            mult = entry[:-1]\n            srcset[float(mult)] = entry\n        else:\n            raise ExtensionError(f'srcset argument {entry!r} is invalid.')\n    return srcset\n\n","sourceCodeStart":618,"sourceCodeEnd":654,"githubUrl":"https://github.com/matplotlib/matplotlib/blob/b379c1b69e012b142c0f496a52bcb30513802d72/lib/matplotlib/sphinxext/plot_directive.py#L618-L654","documentation":"The conf.py option plot_formats tells the plot directive which image formats to emit. Valid entries are plain strings ('png'), strings with dpi ('png:80'), or (suffix, dpi) tuples/lists of exactly length 2. Any other shape - a 3-element tuple, a bare int, a dict - raises PlotError inside get_plot_formats when the first plot is rendered.","triggerScenarios":"plot_formats = [('png', 80, 'extra')] in conf.py; plot_formats = [100]; plot_formats = ['png', {'svg': 90}]; configs written for sphinx-gallery, whose plot_formats shape differs.","commonSituations":"Misreading the tuple arity or argument order; trying to attach extra per-format options; migrating conf.py between doc toolchains.","solutions":["Use plain strings: plot_formats = ['png', 'svg']","Or suffix:dpi strings: plot_formats = ['png:120']","Or 2-tuples: plot_formats = [('png', 120), ('svg', 90)]"],"exampleFix":"# conf.py before\nplot_formats = [('png', 80, 'extra')]  # PlotError: invalid image format\n\n# conf.py after\nplot_formats = [('png', 80)]","handlingStrategy":"validation","validationCode":"def valid_plot_formats(fmts) -> bool:\n    for f in fmts:\n        if isinstance(f, str):\n            continue\n        if isinstance(f, (tuple, list)) and len(f) == 2:\n            continue\n        return False\n    return True\n\n# conf.py\nplot_formats = ['png', ('svg', 90)]\nassert valid_plot_formats(plot_formats), 'plot_formats entries must be str or (suffix, dpi) pairs'","typeGuard":"def is_valid_plot_format_entry(f) -> bool:\n    \"\"\"True if get_plot_formats accepts this entry.\"\"\"\n    return isinstance(f, str) or (isinstance(f, (tuple, list)) and len(f) == 2)","tryCatchPattern":null,"preventionTips":["Write plot_formats entries as 'png', 'png:120', or ('png', 120) - exactly two fields for tuples","Do not port plot_formats values between doc tools (sphinx-gallery uses a different shape)","Validate the list in conf.py so mistakes fail at startup, not at the first rendered plot"],"tags":["matplotlib","sphinx","plot-directive","plot-formats","conf-py","ploterror"],"backgroundTag":"config-validation-failed","analyzedSha":"b379c1b69e012b142c0f496a52bcb30513802d72","analyzedAt":"2026-08-21T23:31:55.468Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}