pypa/pip · error · DirectUrlValidationError
Unexpected type {type(value).__name__} (expected {expected_t
Error message
Unexpected type {type(value).__name__} (expected {expected_type.__name__}) What it means
Raised by `packaging.direct_url._get` when a key is present in the JSON dict but its value is not of the expected type (e.g. `url` is a list instead of str, `editable` is a string instead of bool). This is the schema-validation guard for PEP 610 direct URL JSON, normally wrapped into a `DirectUrlValidationError` with the offending key as `context`.
Source
Thrown at src/pip/_vendor/packaging/direct_url.py:51
class _FromMappingProtocol(Protocol): # pragma: no cover
@classmethod
def _from_dict(cls, d: Mapping[str, Any]) -> Self: ...
_FromMappingProtocolT = TypeVar("_FromMappingProtocolT", bound=_FromMappingProtocol)
def _json_dict_factory(data: list[tuple[str, Any]]) -> dict[str, Any]:
return {key: value for key, value in data if value is not None}
def _get(d: Mapping[str, Any], expected_type: type[_T], key: str) -> _T | None:
"""Get a value from the dictionary and verify it's the expected type."""
if (value := d.get(key)) is None:
return None
if not isinstance(value, expected_type):
raise DirectUrlValidationError(
f"Unexpected type {type(value).__name__} "
f"(expected {expected_type.__name__})",
context=key,
)
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 _DirectUrlRequiredKeyError(key)
return value
def _get_object(
d: Mapping[str, Any], target_type: type[_FromMappingProtocolT], key: str
) -> _FromMappingProtocolT | None:
"""Get a dictionary value from the dictionary and convert it to a dataclass."""View on GitHub (pinned to d7d0d0a394)
Solutions
- Reinstall the package so pip regenerates a spec-compliant `direct_url.json`
- Inspect `<env>/site-packages/<dist>-*.dist-info/direct_url.json` and fix the offending key's type
- Validate the dict against PEP 610 schema before calling `from_dict`
Example fix
// before
DirectUrl.from_dict({'url': 123, 'archive_info': {}})
// after
DirectUrl.from_dict({'url': 'https://example.com/pkg.tar.gz', 'archive_info': {}}) Defensive patterns
Strategy: validation
Validate before calling
def validate_direct_url_dict(d: dict) -> None:
if 'url' in d and not isinstance(d['url'], str):
raise ValueError('url must be str')
if 'subdirectory' in d and not isinstance(d['subdirectory'], str):
raise ValueError('subdirectory must be str') Type guard
def is_direct_url_compatible(d: object) -> bool:
return isinstance(d, dict) and all(
(k not in d) or isinstance(d[k], t)
for k, t in (('url', str), ('subdirectory', str))
) Try / catch
from packaging.direct_url import DirectUrl, DirectUrlValidationError
try:
du = DirectUrl.from_dict(d)
except DirectUrlValidationError as e:
raise ValueError(f'bad direct_url.json: {e}') from e Prevention
- Never hand-edit direct_url.json; let pip regenerate it
- Validate JSON types against PEP 610 schema before calling from_dict
- Reinstall packages whose install metadata errors out
When it happens
Trigger: Calling `DirectUrl.from_dict(d)` (or pip loading a `direct_url.json` from an installed dist) where `d['url']` is not a str, `d['subdirectory']` is not a str, `d['vcs_info']['commit_id']` is not a str, or `d['dir_info']['editable']` is not a bool.
Common situations: Hand-edited `direct_url.json` in site-packages; a tool that emits JSON with coerced types (e.g. quoting booleans); a corrupted install record after an interrupted pip install; a custom installer that writes non-spec records.
Related errors
- Hash values must be strings
- Invalid hash format (expected '<algorithm>=<hash>')
- Algorithm {hash_algorithm!r} used in hash field is not prese
- Algorithm {hash_algorithm!r} used in hash field has differen
- Exactly one of vcs_info, archive_info, dir_info must be pres
AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04).
Data as JSON: /data/errors/21bf6f737f102a10.json.
Report an issue: GitHub.