pypa/pip · error · ValueError

Duplicate group name

Error message

Duplicate group name

What it means

Raised as ValueError in EntryPoint.parse_map at line 2851 when the same group name appears more than once in the entry points metadata. After stripping, if a group is already in the `maps` dict, the second occurrence is rejected because merging would be ambiguous.

Solutions

  1. Merge the duplicate sections into a single section with all entries.
  2. Remove the redundant section header so each group appears exactly once.
  3. Regenerate entry_points.txt via reinstall or setup.py egg_info.
  4. Audit the build process that creates entry_points.txt for append-instead-of-replace bugs.

Example fix

// before: entry_points.txt
// [console_scripts]
// a = pkg:run
// [console_scripts]
// b = pkg:other

// after
// [console_scripts]
// a = pkg:run
// b = pkg:other
Defensive patterns

Strategy: validation

Validate before calling

def merge_duplicate_sections(text: str) -> str:
    from collections import OrderedDict
    sections = OrderedDict()
    current = None
    for line in text.strip().splitlines():
        s = line.strip()
        if s.startswith('[') and s.endswith(']'):
            current = s
            sections.setdefault(current, [])
        elif current:
            sections[current].append(line)
    return '\n'.join(k + '\n' + '\n'.join(v) for k, v in sections.items())

Type guard

def has_unique_sections(text: str) -> bool:
    import re
    headers = re.findall(r'^\[(.+)\]$', text, re.MULTILINE)
    return len(headers) == len(set(headers))

Try / catch

from pkg_resources import EntryPoint
try:
    ep_map = EntryPoint.parse_map(raw_text)
except ValueError as e:
    if 'Duplicate group' in str(e):
        ep_map = EntryPoint.parse_map(merge_duplicate_sections(raw_text))
    else:
        raise

Prevention

When it happens

Trigger: An entry_points.txt file with two '[console_scripts]' sections, or two identical section headers after stripping whitespace. parse_map iterates sections and checks `if group in maps`.

Common situations: Concatenating multiple metadata fragments that repeat section headers; manual editing that duplicates a section; build tools that append to rather than replace entry_points.txt.

Related errors


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

Appendix: source

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

        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), '')
    _, _, value = line.partition(':')
    return safe_version(value.strip()) or None

View on GitHub (pinned to f399c37189)