pypa/pip · error · PylockValidationError

Unexpected type {type(value).__name__} (expected Sequence)

Error message

Unexpected type {type(value).__name__} (expected Sequence)

What it means

Raised as PylockValidationError by _get_sequence in packaging.pylock when a field that must be a list/sequence is instead a str or bytes. str and bytes are technically Sequences in Python, but pylock rejects them to prevent silent character-by-character iteration; the expected value is a real TOML array.

Source

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

    return value


def _get_required(d: Mapping[str, Any], expected_type: type[_T], key: str) -> _T:
    """Get a required value from the dictionary and verify it's the expected type."""
    if (value := _get(d, expected_type, key)) is None:
        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,

View on GitHub (pinned to d7d0d0a394)

Solutions

  1. Wrap the value in TOML array brackets: dependencies = [\"foo\"], wheels = [\"pkg-1.0.whl\"].
  2. Regenerate the lockfile with a spec-compliant tool.
  3. Validate the TOML structure (arrays for sequence fields) before calling PylockFile.from_dict.
  4. Catch PylockValidationError and point the user at the key in e.context.

Example fix

# before
dependencies = \"requests\"
# after
dependencies = [\"requests\"]
Defensive patterns

Strategy: type-guard

Validate before calling

from collections.abc import Sequence

def is_real_sequence(v) -> bool:
    return isinstance(v, Sequence) and not isinstance(v, (str, bytes))

Type guard

from collections.abc import Sequence
from typing import Any

def is_sequence_field(value: Any) -> bool:
    return isinstance(value, Sequence) and not isinstance(value, (str, bytes))

Try / catch

from packaging.pylock import PylockValidationError
try:
    PylockFile.from_dict(data)
except PylockValidationError as e:
    if 'expected Sequence' in str(e):
        wrap_in_array(e.context)

Prevention

When it happens

Trigger: Loading pylock.toml where 'dependencies = \"foo\"' (string instead of array), 'wheels = \"pkg.whl\"', or any array field is given a scalar string. The error context identifies the key.

Common situations: Hand-writing TOML and forgetting the array brackets; converting from a format that collapses single-element lists to scalars; typos like wheels = pkg.whl without quotes/brackets.

Related errors


AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04). Data as JSON: /data/errors/ee86a88f9353c081.json. Report an issue: GitHub.