python-poetry/poetry · error · ValueError

The name [pypi] is reserved for repositories

Error message

The name [pypi] is reserved for repositories

What it means

LegacyRepository.__init__ rejects the repository name 'pypi' because it collides with the built-in PyPIRepository that Poetry registers under that exact name (legacy_repository.py:38-39). Using it would shadow the default PyPI source and break resolution, so construction fails fast.

Source

Thrown at src/poetry/repositories/legacy_repository.py:39

    from packaging.utils import NormalizedName
    from poetry.core.constraints.version import Version
    from poetry.core.packages.utils.link import Link

    from poetry.config.config import Config


class LegacyRepository(HTTPRepository):
    def __init__(
        self,
        name: str,
        url: str,
        *,
        config: Config | None = None,
        disable_cache: bool = False,
        pool_size: int = requests.adapters.DEFAULT_POOLSIZE,
    ) -> None:
        if name == "pypi":
            raise ValueError("The name [pypi] is reserved for repositories")

        super().__init__(
            name,
            url.rstrip("/"),
            config=config,
            disable_cache=disable_cache,
            pool_size=pool_size,
        )

    def package(self, name: str, version: Version) -> Package:
        """
        Retrieve the release information.

        This is a heavy task which takes time.
        We have to download a package to get the dependencies.
        We also need to download every file matching this release
        to get the various hashes.

View on GitHub (pinned to 92b74dcfe3)

Solutions

  1. Choose a distinct source name, e.g. `poetry source add my-pypi <url>`.
  2. If you genuinely want to override the default PyPI URL, configure the PyPI repository's URL instead of adding a new 'pypi' source.
  3. Rename the existing offending entry in pyproject.toml [[tool.poetry.source]] to a non-reserved name.

Example fix

// before
[[tool.poetry.source]]
name = "pypi"
url = "https://mymirror.example.com/simple/"
// after
[[tool.poetry.source]]
name = "mymirror"
url = "https://mymirror.example.com/simple/"
Defensive patterns

Strategy: validation

Validate before calling

RESERVED = {"pypi"}
if source_name.lower() in RESERVED:
    raise ValueError(f"'{source_name}' is reserved; choose another source name")
repo = LegacyRepository(name=source_name, url=url)

Try / catch

try:
    repo = LegacyRepository(name=name, url=url)
except ValueError as e:
    if "reserved" in str(e):
        name = f"{name}-custom"
        repo = LegacyRepository(name=name, url=url)
    raise

Prevention

When it happens

Trigger: Instantiating LegacyRepository(name="pypi", url=...) directly, or running `poetry source add pypi <url>` which constructs a LegacyRepository with that name.

Common situations: A user adding a custom/legacy source and carelessly naming it 'pypi'; copy-pasting a source config that reused the reserved name.

Related errors


AI-assisted analysis of python-poetry/poetry@92b74dcfe3 (2026-08-04). Data as JSON: /data/errors/4087aa46035d2581.json. Report an issue: GitHub.