nodejs/node · error · InvalidWheelFilename
Invalid project name: {filename}
Error message
Invalid project name: {filename} What it means
InvalidWheelFilename raised when the name segment of the wheel filename is invalid per PEP 427 escaping rules: it contains '__' (the escape sequence for a literal dash) in an illegal position, or it fails the ^[\w\d._]*$ regex (e.g. contains spaces or other punctuation).
Source
Thrown at tools/gyp/pylib/packaging/utils.py:122
filename: str,
) -> Tuple[NormalizedName, Version, BuildTag, FrozenSet[Tag]]:
if not filename.endswith(".whl"):
raise InvalidWheelFilename(
f"Invalid wheel filename (extension must be '.whl'): {filename}"
)
filename = filename[:-4]
dashes = filename.count("-")
if dashes not in (4, 5):
raise InvalidWheelFilename(
f"Invalid wheel filename (wrong number of parts): {filename}"
)
parts = filename.split("-", dashes - 2)
name_part = parts[0]
# See PEP 427 for the rules on escaping the project name.
if "__" in name_part or re.match(r"^[\w\d._]*$", name_part, re.UNICODE) is None:
raise InvalidWheelFilename(f"Invalid project name: {filename}")
name = canonicalize_name(name_part)
try:
version = Version(parts[1])
except InvalidVersion as e:
raise InvalidWheelFilename(
f"Invalid wheel filename (invalid version): {filename}"
) from e
if dashes == 5:
build_part = parts[2]
build_match = _build_tag_regex.match(build_part)
if build_match is None:
raise InvalidWheelFilename(
f"Invalid build number: {build_part} in '{filename}'"
)
build = cast(BuildTag, (int(build_match.group(1)), build_match.group(2)))
else:View on GitHub (pinned to 1b2de5e052)
Solutions
- Rebuild the wheel with a conformant backend so the name is escaped to ^[\w._]+$ with dashes encoded as '__'.
- Rename the project to use only ASCII letters, digits, underscores, and dots if escaping is the issue.
- Do not hand-edit wheel filenames; regenerate from sdist.
Example fix
# before (space in name part) # 'my pkg-1.0-py3-none-any.whl' # after (rebuilt with normalized name) # 'my_pkg-1.0-py3-none-any.whl'
Defensive patterns
Strategy: validation
Validate before calling
import re
def valid_wheel_name_part(filename: str) -> bool:
if not filename.endswith('.whl'):
return False
name_part = filename[:-4].split('-')[0]
return '__' not in name_part and bool(re.match(r'^[\w\d._]*$', name_part, re.UNICODE)) Try / catch
try:
parse_wheel_filename(fn)
except InvalidWheelFilename as e:
if 'project name' in str(e):
pass # rebuild wheel with normalized name Prevention
- Keep project names to ASCII alphanumerics, ., _, -.
- Let the backend perform PEP 427 name escaping.
- Avoid manual filename construction.
When it happens
Trigger: A wheel filename whose first dash-separated part (before the version) contains '__' inappropriately or non-word characters. This check runs after the dash-count check passes.
Common situations: Project names with unusual characters that the build backend failed to escape correctly, or filenames edited/constructed manually violating the PEP 427 name-escaping convention.
Related errors
- Invalid wheel filename (extension must be '.whl'): {filename
- Invalid wheel filename (wrong number of parts): {filename}
- Invalid wheel filename (invalid version): {filename}
- Invalid build number: {build_part} in '{filename}'
- name is invalid: {name!r}
AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13).
Data as JSON: /api/errors/fe8d64683ccc2f35.
Report an issue: GitHub.