pypa/pip · error · PylockValidationError
Name {name!r} is not normalized
Error message
Name {name!r} is not normalized What it means
Raised as PylockValidationError by _validate_normalized_name in packaging.pylock when a package 'name' field is not in PEP 503 normalized form (lowercase, runs of [-_.] collapsed to a single '-', no other characters). pylock requires names already normalized so comparisons are unambiguous.
Source
Thrown at src/pip/_vendor/packaging/pylock.py:232
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 d7d0d0a394)
Solutions
- Normalize the name with packaging.utils.canonicalize_name before writing it to the lockfile.
- Regenerate the lockfile with a tool that emits normalized names.
- Replace '_', '.', ' ' with '-' and lowercase the string before passing it.
- Catch PylockValidationError and report which name failed normalization.
Example fix
# before name = \"My_Package\" # after name = \"my-package\"
Defensive patterns
Strategy: validation
Validate before calling
from packaging.utils import canonicalize_name
def is_normalized(name: str) -> bool:
return canonicalize_name(name) == name Type guard
import re
_norm_re = re.compile(r'^[a-z0-9]+(-[a-z0-9]+)*$')
def is_normalized_name(name: str) -> bool:
return bool(_norm_re.match(name)) Try / catch
from packaging.pylock import PylockValidationError
try:
PylockFile.from_dict(data)
except PylockValidationError as e:
if 'not normalized' in str(e):
data['name'] = canonicalize_name(data['name']) Prevention
- Apply canonicalize_name before writing names into lockfiles.
- Use a resolver that emits normalized names.
- Validate names with is_normalized_name before from_dict.
- Avoid copy-pasting raw project names.
When it happens
Trigger: Loading pylock.toml with name = \"My_Package\" (underscore), name = \"MyPackage\" (CamelCase), name = \"my..package\" (double dot). The normalized form would be 'my-package'.
Common situations: Generating a lockfile from project metadata without applying canonicalize_name; mixing normalized and raw names across dependencies; copy-pasting a project name from pyproject [project].name into pylock.
Related errors
- Unexpected type {type(value).__name__} (expected {expected_t
- Unexpected type {type(value).__name__} (expected Sequence)
- Unexpected type {type(item).__name__} (expected {expected_it
- path or url must be provided
- At least one hash must be provided
AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04).
Data as JSON: /data/errors/5d507e95c607c3d0.json.
Report an issue: GitHub.