matplotlib/matplotlib · error · ValueError

Unknown artist properties: %s

Error message

Unknown artist properties: %s

What it means

After validate_cycler() (lib/matplotlib/rcsetup.py:936) obtains a Cycler (from a string or directly), it checks that every key is a known artist property: keys must be a subset of _prop_validators | _prop_aliases. Unknown keys raise ValueError listing them. This is the same whitelist that cycler() enforces, applied when you assign a pre-built Cycler or a string to rcParams['axes.prop_cycle'].

Source

Thrown at lib/matplotlib/rcsetup.py:936

    raise ValueError(f"{loc} is not a valid legend location.")


def validate_cycler(s):
    """Return a Cycler object from a string repr or the object itself."""
    if isinstance(s, str):
        try:
            s = _parse_cycler_string(s)
        except Exception as e:
            raise ValueError(f"{s!r} is not a valid cycler construction: {e}"
                             ) from e
    if isinstance(s, Cycler):
        cycler_inst = s
    else:
        raise ValueError(f"Object is not a string or Cycler instance: {s!r}")

    unknowns = cycler_inst.keys - (set(_prop_validators) | set(_prop_aliases))
    if unknowns:
        raise ValueError("Unknown artist properties: %s" % unknowns)

    # Not a full validation, but it'll at least normalize property names
    # A fuller validation would require v0.10 of cycler.
    checker = set()
    for prop in cycler_inst.keys:
        norm_prop = _prop_aliases.get(prop, prop)
        if norm_prop != prop and norm_prop in cycler_inst.keys:
            raise ValueError(f"Cannot specify both {norm_prop!r} and alias "
                             f"{prop!r} in the same prop_cycle")
        if norm_prop in checker:
            raise ValueError(f"Another property was already aliased to "
                             f"{norm_prop!r}. Collision normalizing {prop!r}.")
        checker.update([norm_prop])

    # This is just an extra-careful check, just in case there is some
    # edge-case I haven't thought of.
    assert len(checker) == len(cycler_inst.keys)

View on GitHub (pinned to b379c1b69e)

Solutions

  1. Use from matplotlib import cycler (the validating wrapper) so bad keys fail at build time with a clearer error
  2. Rename the key to a valid property or alias (color, lw, ls, fc, ec, mfc, mec, mew, ms, ...)
  3. Inspect the whitelist: from matplotlib.rcsetup import _prop_validators, _prop_aliases

Example fix

# before
from cycler import cycler
mpl.rcParams['axes.prop_cycle'] = cycler(colour=['r', 'g', 'b'])
# after
from matplotlib import cycler
mpl.rcParams['axes.prop_cycle'] = cycler(color=['r', 'g', 'b'])
Defensive patterns

Strategy: validation

Validate before calling

from matplotlib.rcsetup import _prop_validators, _prop_aliases
KNOWN = set(_prop_validators) | set(_prop_aliases)
cyc = cycler.cycler(**cfg)
unknown = cyc.keys - KNOWN
if unknown:
    raise ValueError(f'unknown artist properties: {sorted(unknown)}')
mpl.rcParams['axes.prop_cycle'] = cyc

Type guard

from matplotlib.rcsetup import _prop_validators, _prop_aliases
def has_only_known_props(cyc):
    return cyc.keys <= (set(_prop_validators) | set(_prop_aliases))

Try / catch

try:
    mpl.rcParams['axes.prop_cycle'] = cyc
except ValueError as e:
    if 'Unknown artist properties' in str(e):
        mpl.rcParams['axes.prop_cycle'] = cycler(color=list(cyc.by_key().values())[0])
    else:
        raise

Prevention

When it happens

Trigger: mpl.rcParams['axes.prop_cycle'] = cycler.cycler(foo=['a','b']) (raw cycler package, no validation); a Cycler built with a typo'd key then assigned to rcParams; string form "cycler(colour='rgb')".

Common situations: Bypassing matplotlib.cycler by importing cycler.cycler directly, which skips validation at build time so the failure surfaces later at rcParams assignment; merging palette dicts from other tools that use non-Artist keys.

Related errors


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