pypa/pip · error · DistlibException
Ill-formed name/version string: '%s'
Error message
Ill-formed name/version string: '%s'
What it means
Raised by parse_name_and_version() when its input does not match NAME_VERSION_RE, the expected 'name (version)' form used in metadata fields like Provides-Dist / Obsoletes-Dist. A DistlibException 'Ill-formed name/version string' indicates the string is not in the canonical 'foo (1.0)' shape.
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 d7d0d0a394)
Solutions
- Provide the string in 'Name (Version)' form: 'foo (1.0)'.
- If parsing a filename, use a filename parser instead and assemble 'name (version)' explicitly.
- Pre-validate with the NAME_VERSION_RE regex (or packaging.utils) before calling parse_name_and_version().
Example fix
// before
parse_name_and_version('requests-2.31.0')
// after
parse_name_and_version('requests (2.31.0)') Defensive patterns
Strategy: validation
Validate before calling
from distlib.util import NAME_VERSION_RE
def safe_parse_nv(p):
if not NAME_VERSION_RE.match(p):
raise ValueError('not in Name (Version) form: %r' % p)
from distlib.util import parse_name_and_version
return parse_name_and_version(p) Try / catch
from distlib.util import parse_name_and_version, DistlibException
try:
name, version = parse_name_and_version(value)
except DistlibException as e:
if 'Ill-formed name/version string' in str(e):
name, version = alternative_parse(value)
else:
raise Prevention
- Pass metadata values in 'Name (Version)' form, not filenames.
- Pre-validate against NAME_VERSION_RE before calling parse_name_and_version().
- Use packaging.utils for filename-based name/version extraction.
When it happens
Trigger: parse_name_and_version('foo 1.0') (no parens), parse_name_and_version('foo'), parse_name_and_version('foo-1.0.tar.gz'), or any value not matching 'Name (Version)'.
Common situations: Reading metadata fields that are inconsistently formatted, parsing sdist filenames instead of metadata values, or legacy metadata that omits parentheses.
Related errors
- Invalid specification '%s'
- Invalid version: {version!r}
- Metadata 1.2 mandates PEP 440 version, but {dist_verstr!r} i
- invalid version: %s
- invalid constraint: %s
AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04).
Data as JSON: /data/errors/96377fd1d5d99732.json.
Report an issue: GitHub.