{"id":"375188ad72aab7df","repo":"pypa/pip","slug":"name-is-invalid-name-r","errorCode":null,"errorMessage":"name is invalid: {name!r}","messagePattern":"name is invalid: (.+?)","errorType":"validation","errorClass":"InvalidName","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/packaging/utils.py","lineNumber":92,"sourceCode":"\n    If **validate** is true, then the function will check if **name** is a valid\n    distribution name before normalizing.\n\n    :param str name: The name to normalize.\n    :param bool validate: Check whether the name is a valid distribution name.\n    :raises InvalidName: If **validate** is true and the name is not an\n        acceptable distribution name.\n\n    >>> from packaging.utils import canonicalize_name\n    >>> canonicalize_name(\"Django\")\n    'django'\n    >>> canonicalize_name(\"oslo.concurrency\")\n    'oslo-concurrency'\n    >>> canonicalize_name(\"requests\")\n    'requests'\n    \"\"\"\n    if validate and not _validate_regex.fullmatch(name):\n        raise InvalidName(f\"name is invalid: {name!r}\")\n    # Ensure all ``.`` and ``_`` are ``-``\n    # Emulates ``re.sub(r\"[-_.]+\", \"-\", name).lower()`` from PEP 503\n    # Much faster than re, and even faster than str.translate\n    value = name.lower().replace(\"_\", \"-\").replace(\".\", \"-\")\n    # Condense repeats (faster than regex)\n    while \"--\" in value:\n        value = value.replace(\"--\", \"-\")\n    return cast(\"NormalizedName\", value)\n\n\ndef is_normalized_name(name: str) -> bool:\n    \"\"\"\n    Check if a name is already normalized (i.e. :func:`canonicalize_name` would\n    roundtrip to the same value).\n\n    :param str name: The name to check.\n\n    >>> from packaging.utils import is_normalized_name","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_vendor/packaging/utils.py#L74-L110","documentation":"Raised by `canonicalize_name(name, *, validate=True)` when `name` does not match the distribution-name regex `^[a-z0-9]([a-z0-9._-]*[a-z0-9])?$` (single alphanumeric char, or alphanumeric start+end with `[a-z0-9._-]` in between). This is the Core-metadata 'Name' spec; a failing value is not a legal PyPI project name. Note `validate` defaults to `False`, so you only hit this by opting in.","triggerScenarios":"Calling `canonicalize_name('', validate=True)`, `canonicalize_name('.dotted', validate=True)`, names with leading/trailing dots/underscores/hyphens, empty string, or names containing whitespace or non-ASCII punctuation. The check is `_validate_regex.fullmatch(name)` is falsy.","commonSituations":"User-supplied or config-derived package names that were never sanitized; names with a trailing `-` from a sloppy split; empty name after stripping; non-ASCII characters; mixing `validate=True` into a previously permissive code path during an upgrade.","solutions":["Sanitize/trim the name before calling: strip, remove leading/trailing `._-`, ensure at least one alphanumeric character.","Drop the `validate=True` flag if you only need normalization and tolerate legacy names.","Fix the upstream source of the name (config file, CLI arg, metadata).","Pre-check with the same regex before calling so you can branch on invalid input."],"exampleFix":"// before\nfrom pip._vendor.packaging.utils import canonicalize_name\ncanonicalize_name(name.strip(), validate=True)  # raises if name is '.foo'\n\n# after\nimport re\n_NAME_RE = re.compile(r\"[a-z0-9]|[a-z0-9][a-z0-9._-]*[a-z0-9]\", re.IGNORECASE | re.ASCII)\nif not _NAME_RE.fullmatch(name):\n    raise ValueError(f\"refusing to canonicalize invalid name: {name!r}\nclean = canonicalize_name(name, validate=True)","handlingStrategy":"validation","validationCode":"import re\n\n_NAME_RE = re.compile(r\"[a-z0-9]|[a-z0-9][a-z0-9._-]*[a-z0-9]\", re.IGNORECASE | re.ASCII)\n\ndef is_valid_name(name: str) -> bool:\n    return bool(_NAME_RE.fullmatch(name))","typeGuard":"import re\n_NAME_RE = re.compile(r\"[a-z0-9]|[a-z0-9][a-z0-9._-]*[a-z0-9]\", re.IGNORECASE | re.ASCII)\n\ndef is_valid_distribution_name(name: object) -> bool:\n    return isinstance(name, str) and bool(_NAME_RE.fullmatch(name))","tryCatchPattern":"from pip._vendor.packaging.utils import canonicalize_name, InvalidName\n\ntry:\n    norm = canonicalize_name(raw, validate=True)\nexcept InvalidName:\n    norm = canonicalize_name(raw.strip().strip('._-'), validate=False)","preventionTips":["Sanitize names (strip, remove leading/trailing `._-`) before validating.","Only opt into `validate=True` when the name comes from untrusted/user input.","Pre-check with the distribution-name regex to give actionable errors."],"tags":["python","packaging","utils","validation","pep503","metadata"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}