pypa/pip · error · PylockValidationError
Name is not normalized
Error message
Name {name!r} is not normalized What it means
Raised by _validate_normalized_name in pylock.py:238-242, invoked for the package 'name' and for each 'extras' entry. The value must already be PEP 503 normalized (lowercase, with runs of '-', '_', '.' collapsed to a single '-'); otherwise PylockValidationError is raised.
Solutions
- Normalize the name first with packaging.utils.canonicalize_name before writing it (e.g. 'My_Package' -> 'my-package').
Example fix
# before [[packages]] name = "My_Package" # after [[packages]] name = "my-package"
Defensive patterns
Strategy: validation
Validate before calling
from packaging.utils import canonicalize_name, is_normalized_name
def normalized(name: str) -> str:
return canonicalize_name(name)
def already_normalized(name: str) -> bool:
return is_normalized_name(name)
Type guard
from packaging.utils import is_normalized_name, NormalizedName
def is_normalized_pkgname(name: str) -> bool:
return is_normalized_name(name)
Try / catch
from packaging.pylock import Pylock, PylockValidationError
try:
Pylock.from_dict(d)
except PylockValidationError as e:
...
Prevention
- Run names through packaging.utils.canonicalize_name before writing them to a pylock file.
- Treat PyPI display names as un-normalized input.
When it happens
Trigger: In pylock TOML: name = "My_Package", name = "Foo.Bar", name = "Requests", or extras = ["Test_Extra"].
Common situations: Copying a PyPI display/project name verbatim; carrying underscores or mixed case over from setup.py; tooling that does not canonicalize before emitting the lock file.
Related errors
- Name in is not consistent with package name
- Name in is not consistent with package name
- At least one hash must be provided
- Cannot determine sdist filename
- Cannot determine wheel filename
AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08).
Data as JSON: /api/errors/5d507e95c607c3d0.
Report an issue: GitHub.
Appendix: source
Thrown at src/pip/_vendor/packaging/pylock.py:241
except Exception as e:
raise PylockValidationError(e, context=f"{key}[{len(result)}]") from e
return result
def _get_required_sequence_of_objects(
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:View on GitHub (pinned to f399c37189)