pypa/pip · error · DistlibException
Ill-formed name/version string
Error message
Ill-formed name/version string: '%s'
What it means
Raised as DistlibException by distlib.util.parse_name_and_version when the input string does not match NAME_VERSION_RE, the 'name (version)' form used in Provides-Dist metadata. The regex expects a name (word chars, spaces, dots, hyphens) followed by a parenthesized version with no spaces inside the parens. Anything else (missing parens, empty version, stray characters) is rejected.
Solutions
- Convert the input to 'Name (Version)' form first, e.g. via split_filename() to get (name, version) then format it.
- Use parse_requirement() for PEP 508 requirement strings instead of parse_name_and_version.
- Pre-validate with a regex: re.match(r'[\w .-]+\s*\(\s*[^\s)]+\)\s*$', s).
Example fix
# before
parse_name_and_version('requests-2.25.1')
# after
name, ver, _ = split_filename('requests-2.25.1')
parse_name_and_version('%s (%s)' % (name, ver)) Defensive patterns
Strategy: validation
Validate before calling
from distlib.util import NAME_VERSION_RE
def is_name_version(s):
return bool(NAME_VERSION_RE.match(s)) Type guard
def is_provides_dist_form(s: str) -> bool:
import re
return isinstance(s, str) and bool(re.match(r'[\w .-]+\s*\(\s*[^\s)]+\)\s*$', s)) Try / catch
from distlib.util import DistlibException
try:
parse_name_and_version(s)
except DistlibException:
name, ver, _ = split_filename(s)
parse_name_and_version('%s (%s)' % (name, ver)) Prevention
- Use split_filename() for filename-derived strings.
- Pre-format to 'Name (Version)' before parse_name_and_version.
When it happens
Trigger: parse_name_and_version('requests-2.25.1') (missing parens), parse_name_and_version('pkg ()') (empty version), parse_name_and_version('pkg 1.0'), or any string not in the canonical 'Name (Version)' metadata form.
Common situations: Feeding filename-derived strings or 'Name-Version' tuples into a function that expects metadata 'Provides-Dist' format; parsing project list output that uses dashes instead of parens.
Related errors
- Invalid specification
- Badly formatted data
- Error parsing entry points for
- Error parsing entry points for
- Invalid requirement
AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08).
Data as JSON: /api/errors/96377fd1d5d99732.
Report an issue: GitHub.
Appendix: source
Thrown at src/pip/_vendor/distlib/util.py:897
# Allow spaces in name because of legacy dists like "Twisted Core"
NAME_VERSION_RE = re.compile(r'(?P<name>[\w .-]+)\s*'
r'\(\s*(?P<ver>[^\s)]+)\)$')
def parse_name_and_version(p):
"""
A utility method used to get name and version from a string.
From e.g. a Provides-Dist value.
:param p: A value in a form 'foo (1.0)'
:return: The name and version as a tuple.
"""
m = NAME_VERSION_RE.match(p)
if not m:
raise DistlibException('Ill-formed name/version string: \'%s\'' % p)
d = m.groupdict()
return d['name'].strip().lower(), d['ver']
def get_extras(requested, available):
result = set()
requested = set(requested or [])
available = set(available or [])
if '*' in requested:
requested.remove('*')
result |= available
for r in requested:
if r == '-':
result.add(r)
elif r.startswith('-'):
unwanted = r[1:]
if unwanted not in available:
logger.warning('undeclared extra: %s' % unwanted)View on GitHub (pinned to f399c37189)