pypa/pip · error · PylockValidationError

Unexpected type (expected )

Error message

Unexpected type {type(item).__name__} (expected {expected_item_type.__name__})

What it means

Raised by _get_sequence in pylock.py:139-145 when iterating a TOML array: each element is checked against the expected item type (e.g. Mapping for dependencies, str for extras/dependency-groups). A wrong-typed element raises PylockValidationError with context 'key[i]'.

Solutions

  1. Make every element of the array the spec-required type (tables where Mapping is expected, strings where str is expected).

Example fix

# before
[[packages]]
dependencies = [{ name = "x" }, "y"]
# after
[[packages]]
dependencies = [{ name = "x" }, { name = "y" }]
Defensive patterns

Strategy: validation

Validate before calling

from collections.abc import Mapping, Sequence

def array_items_typed(value, item_type: type) -> bool:
    return isinstance(value, Sequence) and all(isinstance(i, item_type) for i in value)

Try / catch

from packaging.pylock import Pylock, PylockValidationError

try:
    Pylock.from_dict(d)
except PylockValidationError as e:
    # e.context is 'key[i]'
    ...

Prevention

When it happens

Trigger: In pylock TOML: dependencies = [{name = "x"}, "y"] (a string element among table elements), dependency-groups = ["dev", 42] (int element where str expected), attestation-identities = [{kind="..."}, "bad"].

Common situations: A mixed-type array; a stray scalar accidentally placed inside an array of tables; copy-paste leaving a placeholder string in a list.

Related errors


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

Appendix: source

Thrown at src/pip/_vendor/packaging/pylock.py:141

        raise _PylockRequiredKeyError(key)
    return value


def _get_sequence(
    d: Mapping[str, Any], expected_item_type: type[_T], key: str
) -> Sequence[_T] | None:
    """Get a list value from the dictionary and verify it's the expected items type."""
    if (value := _get(d, Sequence, key)) is None:  # type: ignore[type-abstract]
        return None
    if isinstance(value, (str, bytes)):
        # special case: str and bytes are Sequences, but we want to reject it
        raise PylockValidationError(
            f"Unexpected type {type(value).__name__} (expected Sequence)",
            context=key,
        )
    for i, item in enumerate(value):
        if not isinstance(item, expected_item_type):
            raise PylockValidationError(
                f"Unexpected type {type(item).__name__} "
                f"(expected {expected_item_type.__name__})",
                context=f"{key}[{i}]",
            )
    return value


def _get_as(
    d: Mapping[str, Any],
    expected_type: type[_T],
    target_type: Callable[[_T], _T2],
    key: str,
) -> _T2 | None:
    """Get a value from the dictionary, verify it's the expected type,
    and convert to the target type.

    This assumes the target_type constructor accepts the value.
    """

View on GitHub (pinned to f399c37189)