pypa/pip · error · PylockValidationError
path or url must be provided
Error message
path or url must be provided
What it means
Raised as PylockValidationError by _validate_path_url in packaging.pylock when both 'path' and 'url' are missing/empty for an archive, sdist, wheel, vcs, or directory entry. At least one locator is required so the artifact can be resolved.
Source
Thrown at src/pip/_vendor/packaging/pylock.py:238
d: Mapping[str, Any], target_item_type: type[_FromMappingProtocolT], key: str
) -> Sequence[_FromMappingProtocolT]:
"""Get a required list value from the dictionary and convert its items to a
dataclass."""
if (result := _get_sequence_of_objects(d, target_item_type, key)) is None:
raise _PylockRequiredKeyError(key)
return result
def _validate_normalized_name(name: str) -> NormalizedName:
"""Validate that a string is a NormalizedName."""
if not is_normalized_name(name):
raise PylockValidationError(f"Name {name!r} is not normalized")
return NormalizedName(name)
def _validate_path_url(path: str | None, url: str | None) -> None:
if not path and not url:
raise PylockValidationError("path or url must be provided")
def _path_name(path: str | None) -> str | None:
if not path:
return None
# If the path is relative it MAY use POSIX-style path separators explicitly
# for portability
if "/" in path:
return path.rsplit("/", 1)[-1]
elif "\\" in path:
return path.rsplit("\\", 1)[-1]
else:
return path
def _url_name(url: str | None) -> str | None:
if not url:
return NoneView on GitHub (pinned to d7d0d0a394)
Solutions
- Add a 'url' (preferred for published artifacts) or 'path' (for local) to the offending table.
- Regenerate the lockfile so the resolver fills in the locator.
- Check for case/spelling mistakes in the key name.
- Catch the error and report the package name to the user for fixing.
Example fix
# before
[packages.sdist]
hashes = { sha256 = \"...\" }
# after
[packages.sdist]
url = \"https://files.pypi.org/.../pkg-1.0.tar.gz\"
hashes = { sha256 = \"...\" } Defensive patterns
Strategy: validation
Validate before calling
def has_locator(entry: dict) -> bool:
return bool(entry.get('path')) or bool(entry.get('url')) Type guard
def has_path_or_url(d) -> bool:
return bool(d.get('path')) or bool(d.get('url')) Try / catch
from packaging.pylock import PylockValidationError
try:
PylockFile.from_dict(data)
except PylockValidationError as e:
if 'path or url' in str(e):
add_url_to_entry(e.context) Prevention
- Always set url (or path for local) on sdist/wheel/archive entries.
- Regenerate lockfiles with a resolver that fills locators.
- Check spelling/case of 'path' and 'url' keys.
- Catch and report the offending package.
When it happens
Trigger: A pylock package entry with an [[packages.sdist]] table that omits both path and url; an archive = {} inline table with neither key; a wheel entry where both fields were accidentally deleted.
Common situations: Hand-editing the lockfile and removing the locator; a buggy resolver that wrote an entry before computing the URL; TOML where the key was misspelled (e.g. 'Url' vs 'url').
Related errors
- Cannot determine sdist filename
- Cannot determine wheel filename
- None of vcs, directory, archive must be set if sdist or whee
- Exactly one of vcs, directory, archive must be set if sdist
- Invalid wheel filename {wheel.filename!r}
AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04).
Data as JSON: /data/errors/c09d1847cb436890.json.
Report an issue: GitHub.