matplotlib/matplotlib · error · ValueError
outfile must be a path or a file-like object
Error message
outfile must be a path or a file-like object
What it means
The PostScript/EPS renderer accepts only a filesystem path (str or os.PathLike) or a writable file-like object as its output target. Before computing the page layout it checks the type of `outfile` and raises this ValueError when the object is neither. This protects downstream code that would otherwise fail obscurely when passing the value to open() or calling .write() on it.
Source
Thrown at lib/matplotlib/backends/backend_ps.py:1031
printer(fmt, outfile, dpi=dpi, dsc_comments=dsc_comments,
orientation=orientation, papertype=papertype,
bbox_inches_restore=bbox_inches_restore, **kwargs)
def _print_figure(
self, fmt, outfile, *,
dpi, dsc_comments, orientation, papertype,
bbox_inches_restore=None):
"""
Render the figure to a filesystem path or a file-like object.
Parameters are as for `.print_figure`, except that *dsc_comments* is a
string containing Document Structuring Convention comments,
generated from the *metadata* parameter to `.print_figure`.
"""
is_eps = fmt == 'eps'
if not (isinstance(outfile, (str, os.PathLike))
or is_writable_file_like(outfile)):
raise ValueError("outfile must be a path or a file-like object")
# find the appropriate papertype
width, height = self.figure.get_size_inches()
if is_eps or papertype == 'figure':
paper_width, paper_height = width, height
else:
paper_width, paper_height = orientation.swap_if_landscape(
papersize[papertype])
# center the figure on the paper
xo = 72 * 0.5 * (paper_width - width)
yo = 72 * 0.5 * (paper_height - height)
llx = xo
lly = yo
urx = llx + self.figure.bbox.width
ury = lly + self.figure.bbox.height
rotation = 0View on GitHub (pinned to b379c1b69e)
Solutions
- Pass a path string or pathlib.Path, e.g. fig.savefig('out.eps') or fig.savefig(Path('/tmp/out.eps'))
- If saving in memory, pass a binary writable buffer: fig.savefig(io.BytesIO(), format='eps')
- If passing a file handle, open it in a writable binary mode: open('out.eps', 'wb')
- Check the variable you pass — print(type(outfile)) right before the call to confirm it is str/Path/file-like
Example fix
# before
fig.savefig(42, format='eps') # or savefig(None)
# after
fig.savefig('figure_42.eps', format='eps')
# or in memory:
buf = io.BytesIO()
fig.savefig(buf, format='eps') Defensive patterns
Strategy: type-guard
Validate before calling
import os
def valid_outfile(obj):
return isinstance(obj, (str, os.PathLike)) or (
hasattr(obj, 'write') and callable(obj.write))
# assert valid_outfile(target) before fig.savefig(target, format='eps') Type guard
from os import PathLike
from typing import Protocol, runtime_checkable
@runtime_checkable
class WritableFileLike(Protocol):
def write(self, data) -> int: ...
def is_valid_ps_outfile(o: object) -> bool:
return isinstance(o, (str, PathLike)) or isinstance(o, WritableFileLike) Try / catch
try:
fig.savefig(target, format='eps')
except ValueError as e:
if 'outfile must be a path' in str(e):
raise TypeError(f'bad save target: {target!r}') from e
raise Prevention
- Always build save targets as f-strings or pathlib.Path, never pass raw computed values unchecked
- Log type(outfile) in debug output before saving
- Standardize on Path objects for all save paths in the codebase
When it happens
Trigger: Calling fig.savefig(..., format='ps'/'eps') (or print_ps/print_eps directly) with an outfile that is not a str, pathlib.Path, or an object exposing a writable .write() method — e.g. an int, None, a closed buffer, or a read-only file handle opened with mode 'r'.
Common situations: Scripts that build the output name from a computation that returned None or a number (e.g. savefig(f'fig_{count}' where count is NaN or an int is passed as the whole path), passing io.StringIO (not binary) buffers, or refactoring code that used to write bytes objects. Also passing a file object opened for reading only, which fails the is_writable_file_like check.
Understand the failure class
Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.
Related errors
- cairo has not been compiled with PS support enabled
- Unterminated string starting at {start}
- Unterminated hex string starting at {start}
- unmatched closing token {token}
- opening token {match} closed by {token}
AI-assisted analysis of matplotlib/matplotlib@b379c1b69e (2026-08-21).
Data as JSON: /api/errors/55c0fc811df545b7.
Report an issue: GitHub.