mlflow/mlflow · error · TypeError

Unsupported figure object type: '{type(figure)}'

Error message

Unsupported figure object type: '{type(figure)}'

What it means

log_figure() only accepts matplotlib figure objects and Plotly figure objects; anything else (including plain dicts, bokeh figures, or nested figures) raises this TypeError. The library cannot serialize an unknown figure type to an artifact file.

Source

Thrown at mlflow/tracking/client.py:3098

            # `is_matplotlib_figure` is executed only when `matplotlib` is found in `sys.modules`.
            # This allows logging a `plotly` figure in an environment where `matplotlib` is not
            # installed.
            if "matplotlib" in sys.modules and _is_matplotlib_figure(figure):
                figure.savefig(tmp_path, **save_kwargs)
            elif "plotly" in sys.modules and _is_plotly_figure(figure):
                file_extension = os.path.splitext(artifact_file)[1]
                if file_extension == ".html":
                    save_kwargs.setdefault("include_plotlyjs", "cdn")
                    save_kwargs.setdefault("auto_open", False)
                    figure.write_html(tmp_path, **save_kwargs)
                elif file_extension in [".png", ".jpeg", ".webp", ".svg", ".pdf"]:
                    figure.write_image(tmp_path, **save_kwargs)
                else:
                    raise TypeError(
                        f"Unsupported file extension for plotly figure: '{file_extension}'"
                    )
            else:
                raise TypeError(f"Unsupported figure object type: '{type(figure)}'")

    def log_image(
        self,
        run_id: str,
        image: Union["numpy.ndarray", "PIL.Image.Image", "mlflow.Image"],
        artifact_file: str | None = None,
        key: str | None = None,
        step: int | None = None,
        timestamp: int | None = None,
        synchronous: bool | None = None,
    ) -> None:
        """
        Logs an image in MLflow, supporting two use cases:

        1. Time-stepped image logging:
            Ideal for tracking changes or progressions through iterative processes (e.g.,
            during model training phases).

View on GitHub (pinned to 6a27f2decc)

Solutions

  1. Convert to a supported type: for plotly use plotly.graph_objects.Figure; for matplotlib use matplotlib.figure.Figure (e.g., call .figure on a seaborn axis, or plt.gcf()).
  2. For PIL images or numpy arrays, use client.log_image() instead of log_figure().
  3. For unsupported libraries (bokeh, altair), export to HTML/PNG bytes yourself and log the file via log_artifact().

Example fix

// before
client.log_figure(run_id, ax, "plot.png")  # seaborn axes object

// after
client.log_figure(run_id, ax.figure, "plot.png")
Defensive patterns

Strategy: type-guard

Validate before calling

import matplotlib.figure
from plotly.graph_objs import Figure
if not isinstance(figure, (matplotlib.figure.Figure, Figure)):
    raise TypeError(f"log_figure accepts matplotlib/plotly figures, got {type(figure)}")
client.log_figure(run_id, figure, artifact_file)

Type guard

def is_loggable_figure(fig) -> bool:
    import matplotlib.figure
    from plotly.graph_objs import Figure
    return isinstance(fig, (matplotlib.figure.Figure, Figure))

Try / catch

try:
    client.log_figure(run_id, figure, artifact_file)
except TypeError as e:
    if "Unsupported figure object type" in str(e):
        client.log_artifact(run_id, export_figure_to_file(figure), artifact_file)
    else:
        raise

Prevention

When it happens

Trigger: client.log_figure(run_id, some_non_figure_object, "fig.png") where the object is not a matplotlib.figure.Figure or plotly figure (e.g., a seaborn axis-level object passed without .fig access, a bokeh figure, or a PIL image mistakenly routed to log_figure).

Common situations: Passing a PIL image or numpy array — those belong in log_image(); passing seaborn plots (some return axes, not figures); version changes where a custom plot library figure was expected to be supported but isn't.

Related errors


AI-assisted analysis of mlflow/mlflow@6a27f2decc (2026-08-29). Data as JSON: /api/errors/70f197cbb06d2af1. Report an issue: GitHub.