{"record":{"id":"1cd213457f6547b8","repo":"pypa/pip","slug":"duplicate-group-name","errorCode":null,"errorMessage":"Duplicate group name","messagePattern":"Duplicate group name","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/pkg_resources/__init__.py","lineNumber":2851,"sourceCode":"        cls,\n        data: str | Iterable[str] | dict[str, str | Iterable[str]],\n        dist: Distribution | None = None,\n    ):\n        \"\"\"Parse a map of entry point groups\"\"\"\n        _data: Iterable[tuple[str | None, str | Iterable[str]]]\n        if isinstance(data, dict):\n            _data = data.items()\n        else:\n            _data = split_sections(data)\n        maps: dict[str, dict[str, Self]] = {}\n        for group, lines in _data:\n            if group is None:\n                if not lines:\n                    continue\n                raise ValueError(\"Entry points must be listed in groups\")\n            group = group.strip()\n            if group in maps:\n                raise ValueError(\"Duplicate group name\", group)\n            maps[group] = cls.parse_group(group, lines, dist)\n        return maps\n\n\ndef _version_from_file(lines):\n    \"\"\"\n    Given an iterable of lines from a Metadata file, return\n    the value of the Version field, if present, or None otherwise.\n    \"\"\"\n\n    def is_version_line(line):\n        return line.lower().startswith('version:')\n\n    version_lines = filter(is_version_line, lines)\n    line = next(iter(version_lines), '')\n    _, _, value = line.partition(':')\n    return safe_version(value.strip()) or None\n","sourceCodeStart":2833,"sourceCodeEnd":2869,"githubUrl":"https://github.com/pypa/pip/blob/f399c3718970b1b0e2478dac5296eb62679a9b86/src/pip/_vendor/pkg_resources/__init__.py#L2833-L2869","documentation":"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.","triggerScenarios":"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`.","commonSituations":"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.","solutions":["Merge the duplicate sections into a single section with all entries.","Remove the redundant section header so each group appears exactly once.","Regenerate entry_points.txt via reinstall or setup.py egg_info.","Audit the build process that creates entry_points.txt for append-instead-of-replace bugs."],"exampleFix":"// before: entry_points.txt\n// [console_scripts]\n// a = pkg:run\n// [console_scripts]\n// b = pkg:other\n\n// after\n// [console_scripts]\n// a = pkg:run\n// b = pkg:other","handlingStrategy":"validation","validationCode":"def merge_duplicate_sections(text: str) -> str:\n    from collections import OrderedDict\n    sections = OrderedDict()\n    current = None\n    for line in text.strip().splitlines():\n        s = line.strip()\n        if s.startswith('[') and s.endswith(']'):\n            current = s\n            sections.setdefault(current, [])\n        elif current:\n            sections[current].append(line)\n    return '\\n'.join(k + '\\n' + '\\n'.join(v) for k, v in sections.items())","typeGuard":"def has_unique_sections(text: str) -> bool:\n    import re\n    headers = re.findall(r'^\\[(.+)\\]$', text, re.MULTILINE)\n    return len(headers) == len(set(headers))\n","tryCatchPattern":"from pkg_resources import EntryPoint\ntry:\n    ep_map = EntryPoint.parse_map(raw_text)\nexcept ValueError as e:\n    if 'Duplicate group' in str(e):\n        ep_map = EntryPoint.parse_map(merge_duplicate_sections(raw_text))\n    else:\n        raise\n","preventionTips":["Merge duplicate section headers into a single section in entry_points.txt.","Audit metadata generation tools for append-instead-of-replace bugs.","Regenerate entry_points.txt after fixing."],"tags":["entry-points","pkg-resources","duplicate","group-name"],"backgroundTag":null,"analyzedSha":"f399c3718970b1b0e2478dac5296eb62679a9b86","analyzedAt":"2026-08-08T23:01:42.227Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}