pypa/pip · error · ValueError
Invalid module name
Error message
Invalid module name
What it means
Raised as ValueError by EntryPoint.__init__ when module_name fails the MODULE regex (`\w+(\.\w+)*$`). Module names must consist of word characters (letters, digits, underscore) and dotted segments; any other character (hyphen, slash, space, leading dot) is rejected. Note the error message is exactly 'Invalid module name' with the offending value as the second argument.
Source
Thrown at src/pip/_vendor/pkg_resources/__init__.py:2693
)?
""",
re.VERBOSE | re.IGNORECASE,
).match
class EntryPoint:
"""Object representing an advertised importable object"""
def __init__(
self,
name: str,
module_name: str,
attrs: Iterable[str] = (),
extras: Iterable[str] = (),
dist: Distribution | None = None,
):
if not MODULE(module_name):
raise ValueError("Invalid module name", module_name)
self.name = name
self.module_name = module_name
self.attrs = tuple(attrs)
self.extras = tuple(extras)
self.dist = dist
def __str__(self):
s = "%s = %s" % (self.name, self.module_name)
if self.attrs:
s += ':' + '.'.join(self.attrs)
if self.extras:
s += ' [%s]' % ','.join(self.extras)
return s
def __repr__(self):
return "EntryPoint.parse(%r)" % str(self)
@overloadView on GitHub (pinned to d7d0d0a394)
Solutions
- Normalize the module name before constructing the EntryPoint: replace '-' with '_' (and any other non-word char) to match Python's import identifier rules.
- Validate with the same regex first: `if MODULE(module_name): EntryPoint(...)` (MODULE = re.compile(r'\w+(\.\w+)*$').match).
- Build EntryPoints via EntryPoint.parse() from a well-formed 'name=module:attr' string, which applies the same validation through its pattern.
Example fix
// before
ep = EntryPoint('cli', 'my-pkg.cli', ['main']) # ValueError: Invalid module name
// after
module_name = 'my-pkg.cli'.replace('-', '_')
ep = EntryPoint('cli', module_name, ['main']) # 'my_pkg.cli' — OK Defensive patterns
Strategy: validation
Validate before calling
import re
MODULE = re.compile(r'\w+(\.\w+)*$').match
def safe_entry_point(name, module_name, attrs=()):
if not MODULE(module_name):
# normalize hyphens and other common project-name chars
module_name = re.sub(r'[^\w.]', '_', module_name)
if not MODULE(module_name):
raise ValueError(f'Invalid module name: {module_name!r}')
from pkg_resources import EntryPoint
return EntryPoint(name, module_name, attrs) Type guard
import re
MODULE = re.compile(r'\w+(\.\w+)*$').match
def is_valid_module_name(name: str) -> bool:
return isinstance(name, str) and bool(MODULE(name)) Try / catch
try:
ep = EntryPoint(name, module_name, attrs)
except ValueError as e:
if 'Invalid module name' in str(e):
module_name = module_name.replace('-', '_')
ep = EntryPoint(name, module_name, attrs)
else:
raise Prevention
- Normalize project names (replace '-' with '_') before using as a module name.
- Validate module_name with the MODULE regex before constructing EntryPoint.
- Build EntryPoints via parse() from a well-formed 'name=module:attr' string.
When it happens
Trigger: Constructing an EntryPoint(name, module_name, ...) directly with a module_name containing invalid characters — most commonly a hyphenated project name used verbatim as a module ('my-pkg.app') instead of the underscored import name ('my_pkg.app').
Common situations: Auto-generating entry points from PyPI project names (which allow hyphens) without normalizing to the import name; typos in entry_points.txt; programmatic EntryPoint creation from untrusted/user input.
Related errors
- Invalid specification '%s'
- Cannot use '--only-dependencies' in combination with {confli
- When restricting platform and interpreter constraints using
- Can not use any platform or abi specific options unless inst
- Platform and interpreter constraints using --python-version,
AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04).
Data as JSON: /data/errors/439b81e94083b47a.json.
Report an issue: GitHub.