{"record":{"id":"439b81e94083b47a","repo":"pypa/pip","slug":"invalid-module-name","errorCode":null,"errorMessage":"Invalid module name","messagePattern":"Invalid module name","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/pkg_resources/__init__.py","lineNumber":2693,"sourceCode":"    )?\n    \"\"\",\n    re.VERBOSE | re.IGNORECASE,\n).match\n\n\nclass EntryPoint:\n    \"\"\"Object representing an advertised importable object\"\"\"\n\n    def __init__(\n        self,\n        name: str,\n        module_name: str,\n        attrs: Iterable[str] = (),\n        extras: Iterable[str] = (),\n        dist: Distribution | None = None,\n    ):\n        if not MODULE(module_name):\n            raise ValueError(\"Invalid module name\", module_name)\n        self.name = name\n        self.module_name = module_name\n        self.attrs = tuple(attrs)\n        self.extras = tuple(extras)\n        self.dist = dist\n\n    def __str__(self):\n        s = \"%s = %s\" % (self.name, self.module_name)\n        if self.attrs:\n            s += ':' + '.'.join(self.attrs)\n        if self.extras:\n            s += ' [%s]' % ','.join(self.extras)\n        return s\n\n    def __repr__(self):\n        return \"EntryPoint.parse(%r)\" % str(self)\n\n    @overload","sourceCodeStart":2675,"sourceCodeEnd":2711,"githubUrl":"https://github.com/pypa/pip/blob/f399c3718970b1b0e2478dac5296eb62679a9b86/src/pip/_vendor/pkg_resources/__init__.py#L2675-L2711","documentation":"Raised as ValueError in EntryPoint.__init__ when module_name fails the MODULE regex (`\\w+(\\.\\w+)*$`). This regex requires dotted identifiers composed of word characters only. An invalid module name means the EntryPoint cannot be used to import anything. The check is at line 2692-2693.","triggerScenarios":"Directly constructing EntryPoint(name, module_name, ...) with a module_name containing invalid characters (spaces, hyphens, leading digits mixed with dots, empty string, etc.). Also triggered indirectly via EntryPoint.parse if the parsed module group somehow bypasses the parse regex.","commonSituations":"Programmatically building entry points from user input or config without validation; typos in entry_points.txt metadata; dynamically generated entry point strings with package names containing hyphens (should use underscores).","solutions":["Validate the module name with the same regex before construction: `re.match(r'\\w+(\\.\\w+)*$', module_name)`.","Replace hyphens with underscores in package/module names (Python identifiers cannot contain hyphens).","Use EntryPoint.parse() with a well-formed string rather than constructing EntryPoint directly.","Sanitize user-provided names by stripping non-word characters."],"exampleFix":"// before\nep = EntryPoint('cli', 'my-package.cli', ('main',))\n# ValueError: Invalid module name 'my-package.cli'\n\n// after\nep = EntryPoint('cli', 'my_package.cli', ('main',))","handlingStrategy":"validation","validationCode":"import re\nMODULE = re.compile(r'\\w+(\\.\\w+)*$').match\ndef safe_module_name(name: str) -> bool:\n    return bool(MODULE(name))","typeGuard":"import re\ndef is_valid_module_name(name: str) -> bool:\n    return bool(re.match(r'^\\w+(\\.\\w+)*$', name)) and len(name) > 0\n","tryCatchPattern":"from pkg_resources import EntryPoint\ntry:\n    ep = EntryPoint('cli', module_name, ('main',))\nexcept ValueError:\n    module_name = module_name.replace('-', '_')\n    ep = EntryPoint('cli', module_name, ('main',))\n","preventionTips":["Always validate module names with the same regex before constructing EntryPoint.","Replace hyphens with underscores in package names used as module identifiers.","Prefer EntryPoint.parse() over direct construction for user-provided strings."],"tags":["entry-points","pkg-resources","validation","module-name"],"backgroundTag":null,"analyzedSha":"f399c3718970b1b0e2478dac5296eb62679a9b86","analyzedAt":"2026-08-08T23:01:42.227Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}