pypa/pip · error · ValueError

Entry points must be listed in groups

Error message

Entry points must be listed in groups

What it means

Raised as ValueError in EntryPoint.parse_map at line 2848 when entry point lines appear before any group section header. The split_sections function returns (None, content) for lines before the first '[group]'; if content exists under section=None, it means orphaned lines with no group context.

Solutions

  1. Ensure every entry point line is preceded by a '[group_name]' section header in entry_points.txt.
  2. Add the missing section header at the top of the file.
  3. Regenerate the .egg-info/entry_points.txt by reinstalling or running setup.py egg_info.
  4. Validate metadata files before packaging.

Example fix

// before: entry_points.txt
// mycli = mypkg:main
// [console_scripts]
// other = otherpkg:run

// after
// [console_scripts]
// mycli = mypkg:main
// other = otherpkg:run
Defensive patterns

Strategy: validation

Validate before calling

def ensure_group_header(text: str) -> str:
    lines = text.strip().splitlines()
    if lines and not lines[0].strip().startswith('['):
        lines.insert(0, '[console_scripts]')
    return '\n'.join(lines)

Type guard

def all_lines_under_sections(text: str) -> bool:
    in_section = False
    for line in text.strip().splitlines():
        stripped = line.strip()
        if stripped.startswith('['):
            in_section = True
        elif stripped and '=' in stripped and not in_section:
            return False
    return True

Try / catch

from pkg_resources import EntryPoint
try:
    ep_map = EntryPoint.parse_map(raw_text)
except ValueError as e:
    if 'must be listed in groups' in str(e):
        ep_map = EntryPoint.parse_map(ensure_group_header(raw_text))
    else:
        raise

Prevention

When it happens

Trigger: An entry_points.txt file that has lines before the first '[group]' section header, or a multi-line string passed to parse_map without a leading section. The check `if group is None` with non-empty lines triggers the error.

Common situations: Truncated or hand-edited entry_points.txt missing the section header; copy-paste that drops the '[console_scripts]' line; metadata generation tools that emit raw lines first.

Related errors


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

Appendix: source

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

    @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()
        else:
            _data = split_sections(data)
        maps: dict[str, dict[str, Self]] = {}
        for group, lines in _data:
            if group is None:
                if not lines:
                    continue
                raise ValueError("Entry points must be listed in groups")
            group = group.strip()
            if group in maps:
                raise ValueError("Duplicate group name", group)
            maps[group] = cls.parse_group(group, lines, dist)
        return maps


def _version_from_file(lines):
    """
    Given an iterable of lines from a Metadata file, return
    the value of the Version field, if present, or None otherwise.
    """

    def is_version_line(line):
        return line.lower().startswith('version:')

    version_lines = filter(is_version_line, lines)
    line = next(iter(version_lines), '')

View on GitHub (pinned to f399c37189)