matplotlib/matplotlib · warning · ExecutableNotFoundError

str(_ose)

Error message

str(_ose)

What it means

Same pybind11 constructor path as hinting_factor: supplying `_kerning_factor` to matplotlib.ft2font.FT2Font (src/ft2font_wrapper.cpp:420-426) warns; the value is accepted until removal in 3.13, after which it becomes a TypeError. It also fires indirectly: font_manager._get_font forwards rcParams['text.kerning_factor'] into every FT2Font it creates (font_manager.py:1772, 1688), so setting that rcParam to a non-None int makes each newly instantiated font warn (per-thread font caching means it warns once per font). The leading underscore already marks the kwarg as internal API.

Source

Thrown at lib/matplotlib/__init__.py:417

        # Execute the subprocess specified by args; capture stdout and stderr.
        # Search for a regex match in the output; if the match succeeds, the
        # first group of the match is the version.
        # Return an _ExecInfo if the executable exists, and has a version of
        # at least min_ver (if set); else, raise ExecutableNotFoundError.
        try:
            output = subprocess.check_output(
                args, stderr=subprocess.STDOUT,
                text=True, errors="replace", timeout=30)
        except subprocess.CalledProcessError as _cpe:
            if ignore_exit_code:
                output = _cpe.output
            else:
                raise ExecutableNotFoundError(str(_cpe)) from _cpe
        except subprocess.TimeoutExpired as _te:
            msg = f"Timed out running {cbook._pformat_subprocess(args)}"
            raise ExecutableNotFoundError(msg) from _te
        except OSError as _ose:
            raise ExecutableNotFoundError(str(_ose)) from _ose
        match = re.search(regex, output)
        if match:
            raw_version = match.group(1)
            version = parse_version(raw_version)
            if min_ver is not None and version < parse_version(min_ver):
                raise ExecutableNotFoundError(
                    f"You have {args[0]} version {version} but the minimum "
                    f"version supported by Matplotlib is {min_ver}")
            return _ExecInfo(args[0], raw_version, version)
        else:
            raise ExecutableNotFoundError(
                f"Failed to determine the version of {args[0]} from "
                f"{' '.join(args)}, which output {output}")

    if name in os.environ.get("_MPLHIDEEXECUTABLES", "").split(","):
        raise ExecutableNotFoundError(f"{name} was hidden")

    if name == "dvipng":

View on GitHub (pinned to b379c1b69e)

Solutions

  1. Stop passing `_kerning_factor`; it is underscore-private and its public handle, the `text.kerning_factor` rcParam, is itself deprecated.
  2. If you changed kerning globally, remove the rcParam assignment and rely on default kerning; if you must keep it temporarily, accept that each new font warns once due to caching.
  3. Suppress the specific noise: `warnings.filterwarnings('ignore', message='The _kerning_factor parameter was deprecated')`.
  4. Pin `matplotlib<3.11` only as a stopgap while migrating callers.

Example fix

# before
from matplotlib import ft2font
font = ft2font.FT2Font(path, _kerning_factor=2)

# after
from matplotlib import ft2font
font = ft2font.FT2Font(path)  # private kwarg dropped; use default kerning
Defensive patterns

Strategy: validation

Validate before calling

import matplotlib
from packaging.version import Version
from matplotlib import ft2font

kwargs = {}
if Version(matplotlib.__version__) < Version("3.11"):
    kwargs["_kerning_factor"] = 2
font = ft2font.FT2Font(path, **kwargs)  # kwarg warns in 3.11, TypeError in 3.13

Try / catch

import warnings
import matplotlib as mpl

with warnings.catch_warnings(record=True) as caught:
    warnings.simplefilter("always", mpl.MatplotlibDeprecationWarning)
    font = ft2font.FT2Font(path, _kerning_factor=2)  # last use while migrating
assert not [w for w in caught if "_kerning_factor" in str(w.message)], "still passing the deprecated kwarg"

Prevention

When it happens

Trigger: `ft2font.FT2Font(file, _kerning_factor=123)` (any int; a float like 1.3 raises TypeError first because the C++ signature takes int, per test_ft2font.py:231-238); or `mpl.rcParams['text.kerning_factor'] = 2` followed by any text rendering that instantiates a new font.

Common situations: Typographic code fine-tuning letter spacing for pixel-tight labels; tools built directly on FT2Font; upgrading to 3.11 with a style file or rcParams block that still sets text.kerning_factor, causing warnings during text layout.

Related errors


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