matplotlib/matplotlib · error · ExecutableNotFoundError

Failed to determine the version of {args[0]} from {' '.join(

Error message

Failed to determine the version of {args[0]} from {' '.join(args)}, which output {output}

What it means

Affine2DBase declares transform_affine() as the abstract hook that concrete affine transforms must supply; the base implementation only raises NotImplementedError('Affine subclasses should override this method.'). You hit it when an affine transform object actually executes - the error surfaces from transform()/transform_path() too, since they delegate to transform_affine().

Source

Thrown at lib/matplotlib/__init__.py:428

                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":
        return impl(["dvipng", "-version"], "(?m)^dvipng(?: .*)? (.+)", "1.6")
    elif name == "gs":
        execs = (["gswin32c", "gswin64c", "mgs", "gs"]  # "mgs" for miktex.
                 if sys.platform == "win32" else
                 ["gs"])
        for e in execs:
            try:
                return impl([e, "--version"], "(.*)", "9")
            except ExecutableNotFoundError:
                pass
        message = "Failed to find a Ghostscript installation"

View on GitHub (pinned to b379c1b69e)

Solutions

  1. Subclass Affine2D and override get_matrix() only - Affine2D already implements transform_affine via the matrix machinery
  2. If you must subclass Affine2DBase, implement transform_affine(values) returning the (N, 2) result of applying your 3x3 matrix
  3. Never instantiate Affine2DBase or half-finished subclasses; guard with a factory that asserts the override exists

Example fix

// before
class MyAffine(mtrans.Affine2DBase):
    def get_matrix(self): return self._mtx
a = MyAffine(); a.transform(pts)  # NotImplementedError

// after
class MyAffine(mtrans.Affine2D):
    def get_matrix(self): return self._mtx
a = MyAffine(); a.transform(pts)
Defensive patterns

Strategy: type-guard

Validate before calling

import inspect
for m in ('transform_affine', 'get_matrix'):
    owner = inspect.getmro(type(affine))
    assert any(m in vars(c) for c in owner if c is not mtrans.Affine2DBase), f'{type(affine).__name__} must override {m}'

Type guard

def is_concrete_affine(t) -> bool:
    return isinstance(t, mtrans.Affine2D) or type(t).transform_affine is not mtrans.Affine2DBase.transform_affine

Try / catch

try:
    out = affine.transform(pts)
except NotImplementedError as e:
    if 'Affine subclasses' in str(e):
        raise TypeError(f'{type(affine).__name__} is not a concrete affine') from e
    raise

Prevention

When it happens

Trigger: Subclassing Affine2DBase (instead of Affine2D) and overriding get_matrix() but not transform_affine(); instantiating an intermediate affine base class directly (Affine2DBase(), or an unfinished subclass) and calling .transform(points) on it; tests that instantiate every class in a hierarchy.

Common situations: Writing custom affine transforms (e.g. a lazily-updated matrix cache) while subclassing the wrong base; partially-copied subclass code from matplotlib internals that skips the method; tutorial code that subclasses Affine2DBase to hook get_matrix.

Related errors


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