pypa/pip · error · TypeError

Unexpected marker {marker!r}

Error message

Unexpected marker {marker!r}

What it means

Defensive TypeError in _evaluate_markers (markers.py:325, marked '# pragma: nocover') for a marker element that is neither a list, a tuple, the 'and' string, nor the 'or' string. The parser grammar (_parse_marker) cannot produce such an element, so this branch is effectively unreachable through the public Marker/Requirement APIs.

Source

Thrown at src/pip/_vendor/packaging/markers.py:325

                lhs_value = lhs.value
                environment_key = rhs.value
                rhs_value = _lookup_environment(environment, environment_key)

            if not isinstance(lhs_value, str):
                raise UndefinedComparison(
                    f"Set-valued marker {environment_key!r} can only be used "
                    f'with the membership form (e.g. "<name>" in '
                    f"{environment_key}); it cannot appear on the left-hand "
                    f"side of {op.serialize()!r}."
                )
            lhs_value, rhs_value = _normalize(lhs_value, rhs_value, key=environment_key)
            groups[-1].append(_eval_op(lhs_value, op, rhs_value, key=environment_key))
        elif marker == "or":
            groups.append([])
        elif marker == "and":
            pass
        else:  # pragma: nocover
            raise TypeError(f"Unexpected marker {marker!r}")

    return any(all(item) for item in groups)


def _format_full_version(info: sys._version_info) -> str:
    version = f"{info.major}.{info.minor}.{info.micro}"
    kind = info.releaselevel
    if kind != "final":
        version += kind[0] + str(info.serial)
    return version


@functools.cache
def _cached_default_environment() -> Environment:
    """Build the default marker environment for the current Python process.

    The values are derived from process-constant data (the running interpreter
    and the host platform), so this is cached and built only once. The result is

View on GitHub (pinned to f399c37189)

Solutions

  1. Do not mutate _markers directly; always construct via Marker(string) or the __and__/__or__ combinators.
  2. If encountered without direct attribute tampering, file a packaging bug report with the marker string.
Defensive patterns

Strategy: try-catch

Try / catch

from packaging.markers import Marker

try:
    Marker(expr).evaluate()
except TypeError as e:
    # defensive/unexpected internal state; report upstream
    ...

Prevention

When it happens

Trigger: Not reachable via normal parsing. Only by directly assigning a malformed structure to a Marker's private _markers attribute (e.g. in tests/mocking) or via an internal packaging bug.

Common situations: Monkeypatching or hand-building marker._markers in tests with an invalid node type.

Related errors


AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08). Data as JSON: /api/errors/c7e22347e26d7627. Report an issue: GitHub.