pypa/pip · error · ValueError
Duplicate entry point
Error message
Duplicate entry point
What it means
Raised as ValueError in EntryPoint.parse_group at line 2826-2827 when the same entry point name appears more than once within a single group. The dict `this` tracks seen names; a collision means metadata is ambiguous and cannot be resolved deterministically.
Solutions
- Search the entry_points.txt / setup.cfg / pyproject.toml for duplicate names within the same group and remove the stale entry.
- If you need multiple targets, use different entry point names for each.
- Reinstall the package after fixing the metadata so entry_points.txt is regenerated.
- Audit generated entry_points.txt in the .egg-info directory for duplicates.
Example fix
// before: setup.cfg // [options.entry_points] // console_scripts = // mycli = mypkg:main // mycli = otherpkg:run // after // [options.entry_points] // console_scripts = // mycli = mypkg:main
Defensive patterns
Strategy: validation
Validate before calling
def deduplicate_entry_points(lines):
seen = set()
result = []
for line in lines:
name = line.split('=')[0].strip()
if name not in seen:
seen.add(name)
result.append(line)
return result Type guard
def has_no_duplicate_names(lines: list[str]) -> bool:
names = [l.split('=')[0].strip() for l in lines if '=' in l]
return len(names) == len(set(names))
Try / catch
from pkg_resources import EntryPoint
try:
group_map = EntryPoint.parse_group('console_scripts', lines)
except ValueError as e:
if 'Duplicate' in str(e):
# deduplicate and retry
group_map = EntryPoint.parse_group('console_scripts', deduplicate_entry_points(lines))
else:
raise
Prevention
- Deduplicate entry point names within each group before packaging.
- Audit setup.cfg/pyproject.toml entry_points sections for duplicates.
- Regenerate .egg-info after fixing to clear stale metadata.
When it happens
Trigger: An entry_points.txt or setup.cfg [entry_points] section lists two lines with the same left-hand name under the same group. For example, two 'cli = ...' lines under [console_scripts].
Common situations: Merging entry point lists from multiple sources that both define the same name; copy-paste duplication; refactoring that leaves stale entries alongside new ones; automated generation tools that don't deduplicate.
Related errors
- Duplicate group name
- Entry points must be listed in groups
- Error parsing entry points for
- Entry point %r not found
- EntryPoint must be in 'name=module:attrs [extras]' format
AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08).
Data as JSON: /api/errors/f15f5444e18b4985.
Report an issue: GitHub.
Appendix: source
Thrown at src/pip/_vendor/pkg_resources/__init__.py:2827
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()
else:
_data = split_sections(data)
maps: dict[str, dict[str, Self]] = {}
for group, lines in _data:
if group is None:View on GitHub (pinned to f399c37189)