nodejs/node · error · InvalidName

name is invalid: {name!r}

Error message

name is invalid: {name!r}

What it means

packaging.utils.InvalidName raised by canonicalize_name(name, validate=True) when name fails the core-metadata Name regex ^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$ (case-insensitive). Validation is opt-in; the default validate=False path canonicalizes anything without checking.

Source

Thrown at tools/gyp/pylib/packaging/utils.py:45

class InvalidSdistFilename(ValueError):
    """
    An invalid sdist filename was found, users should refer to the packaging user guide.
    """


# Core metadata spec for `Name`
_validate_regex = re.compile(
    r"^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$", re.IGNORECASE
)
_canonicalize_regex = re.compile(r"[-_.]+")
_normalized_regex = re.compile(r"^([a-z0-9]|[a-z0-9]([a-z0-9-](?!--))*[a-z0-9])$")
# PEP 427: The build number must start with a digit.
_build_tag_regex = re.compile(r"(\d+)(.*)")


def canonicalize_name(name: str, *, validate: bool = False) -> NormalizedName:
    if validate and not _validate_regex.match(name):
        raise InvalidName(f"name is invalid: {name!r}")
    # This is taken from PEP 503.
    value = _canonicalize_regex.sub("-", name).lower()
    return cast(NormalizedName, value)


def is_normalized_name(name: str) -> bool:
    return _normalized_regex.match(name) is not None


def canonicalize_version(
    version: Union[Version, str], *, strip_trailing_zero: bool = True
) -> str:
    """
    This is very similar to Version.__str__, but has one subtle difference
    with the way it handles the release segment.
    """
    if isinstance(version, str):
        try:

View on GitHub (pinned to 1b2de5e052)

Solutions

  1. Strip whitespace and confirm the name matches the regex before calling canonicalize_name(validate=True).
  2. Catch InvalidName and surface a user-friendly validation message at the input boundary.
  3. Use is_normalized_name() for a softer check, or canonicalize_name(validate=False) when you only want normalization.

Example fix

# before
name = canonicalize_name(raw, validate=True)

# after
try:
    name = canonicalize_name(raw, validate=True)
except InvalidName:
    raise ValueError(f'Please enter a valid project name: {raw!r}')
Defensive patterns

Strategy: validation

Validate before calling

import re
_name_re = re.compile(r'^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$', re.IGNORECASE)
def is_valid_name(name: str) -> bool:
    return bool(_name_re.match(name))

Type guard

from packaging.utils import canonicalize_name, InvalidName
def valid_name_or_none(name: str):
    try:
        return canonicalize_name(name, validate=True)
    except InvalidName:
        return None

Try / catch

try:
    norm = canonicalize_name(raw, validate=True)
except InvalidName as e:
    raise ValueError(f'Invalid project name: {e}') from e

Prevention

When it happens

Trigger: Calling canonicalize_name(name, validate=True) with a name that is empty, starts/ends with a non-alphanumeric character, contains characters outside [A-Z0-9._-], or is a single underscore/dot/dash.

Common situations: Validating user-typed project names from a form or CLI, or sanitizing package names read from untrusted metadata before publishing.

Related errors


AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13). Data as JSON: /api/errors/38ddd2455e6eae50. Report an issue: GitHub.