{"id":"1cd213457f6547b8","repo":"pypa/pip","slug":"duplicate-group-name","errorCode":null,"errorMessage":"Duplicate group name","messagePattern":"Duplicate group name","errorType":"exception","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/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_vendor/pkg_resources/__init__.py#L2833-L2869","documentation":"Raised by EntryPoint.parse_map when the same '[group]' section header appears more than once in the parsed data. Because the result is a dict keyed by group, a repeated header is ambiguous and pkg_resources rejects it with ValueError('Duplicate group name', group).","triggerScenarios":"entry_points.txt (or a dict passed to parse_map) contains two identical section headers, e.g. two '[console_scripts]' blocks; parse_map encounters the group already in 'maps'.","commonSituations":"Concatenating metadata from multiple sources, a packaging tool that appends a group instead of merging into the existing one, or manual editing that duplicated a header.","solutions":["Merge the entries of the duplicated group under a single '[group]' header.","Regenerate the metadata from a single consolidated entry_points/ pyproject.toml source.","If merging programmatically, accumulate lines per group into a dict before serializing instead of concatenating raw sections."],"exampleFix":"# before\n[console_scripts]\nfoo = a:main\n[console_scripts]\nbar = b:main\n\n# after\n[console_scripts]\nfoo = a:main\nbar = b:main","handlingStrategy":"validation","validationCode":"from configparser import ConfigParser\ncp = ConfigParser()\ncp.read_string(entry_points_txt)\n# ConfigParser merges duplicate sections silently; to detect manually:\nheaders = [ln.strip() for ln in entry_points_txt.splitlines() if ln.strip().startswith('[')]\nassert len(headers) == len(set(headers)), 'duplicate group section'","typeGuard":"def has_unique_groups(text: str) -> bool:\n    seen = set()\n    for line in text.splitlines():\n        s = line.strip()\n        if s.startswith('[') and s.endswith(']'):\n            if s in seen:\n                return False\n            seen.add(s)\n    return True","tryCatchPattern":"try:\n    EntryPoint.parse_map(data)\nexcept ValueError as e:\n    if 'Duplicate group name' in str(e):\n        # merge sections, then retry\n        ...\n    raise","preventionTips":["Merge entry-point sections from multiple packages before serializing.","Use a dict {group: [lines]} when building maps in code."],"tags":["python","pkg-resources","entry-points","metadata","duplicate"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}