pypa/pip · error · ValueError

Invalid group name

Error message

Invalid group name

What it means

Raised as ValueError in EntryPoint.parse_group when the group name fails the MODULE regex (`\w+(\.\w+)*$`). Group names must be valid dotted Python identifiers (e.g. 'console_scripts', 'myapp.commands'). Invalid characters or empty names trigger this at line 2821-2822.

Solutions

  1. Use only word characters and dots in group names: 'console_scripts', 'myapp.plugins', 'pytest11'.
  2. Replace hyphens with underscores in group names.
  3. Validate group names with `re.match(r'\w+(\.\w+)*$', group)` before parsing.
  4. Check the section header in entry_points.txt / setup.cfg for invalid characters.

Example fix

// before: entry_points.txt
// [my-plugin-group]
// entry = mypkg:main
# ValueError: Invalid group name 'my-plugin-group'

// after
// [my_plugin_group]
// entry = mypkg:main
Defensive patterns

Strategy: validation

Validate before calling

import re
MODULE = re.compile(r'\w+(\.\w+)*$').match
def is_valid_group_name(group: str) -> bool:
    return bool(MODULE(group))

Type guard

import re
def is_valid_group(name: str) -> bool:
    return bool(re.match(r'^\w+(\.\w+)*$', name)) and len(name) > 0

Try / catch

from pkg_resources import EntryPoint
try:
    result = EntryPoint.parse_group(group, lines)
except ValueError:
    group = group.replace('-', '_')
    result = EntryPoint.parse_group(group, lines)

Prevention

When it happens

Trigger: Calling EntryPoint.parse_group(group, lines) with a group containing hyphens, spaces, special characters, or other invalid identifier characters. Also fires when entry_points.txt has a malformed section header like [my-group] (hyphens not allowed).

Common situations: Using hyphens instead of underscores or dots in group names in entry_points.txt; typos in section headers; custom plugin group names that don't follow Python identifier conventions.

Related errors


AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08). Data as JSON: /api/errors/82282b6bcdc0e293. Report an issue: GitHub.

Appendix: source

Thrown at src/pip/_vendor/pkg_resources/__init__.py:2822

    @classmethod
    def _parse_extras(cls, extras_spec):
        if not extras_spec:
            return ()
        req = Requirement.parse('x' + extras_spec)
        if req.specs:
            raise ValueError
        return req.extras

    @classmethod
    def parse_group(
        cls,
        group: str,
        lines: _NestedStr,
        dist: Distribution | None = None,
    ):
        """Parse an entry point group"""
        if not MODULE(group):
            raise ValueError("Invalid group name", group)
        this: dict[str, Self] = {}
        for line in yield_lines(lines):
            ep = cls.parse(line, dist)
            if ep.name in this:
                raise ValueError("Duplicate entry point", group, ep.name)
            this[ep.name] = ep
        return this

    @classmethod
    def parse_map(
        cls,
        data: str | Iterable[str] | dict[str, str | Iterable[str]],
        dist: Distribution | None = None,
    ):
        """Parse a map of entry point groups"""
        _data: Iterable[tuple[str | None, str | Iterable[str]]]
        if isinstance(data, dict):
            _data = data.items()

View on GitHub (pinned to f399c37189)