pypa/pip · error · TypeError

Expected str, Requirement, or Distribution

Error message

Expected str, Requirement, or Distribution

What it means

Raised by the module-level get_distribution() when, after converting a string to a Requirement and resolving it via get_provider(), the result is not a Distribution instance. get_provider() returns an IResourceProvider for plain modules and a Distribution only for installed distributions; if you pass a module name that resolves to a resource provider but not a real distribution, the final isinstance check fails and TypeError is raised. The accepted inputs are str, Requirement, or an already-built Distribution.

Source

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

        return True

    # XXX Linux and other platforms' special cases should go here
    return False


@overload
def get_distribution(dist: _DistributionT) -> _DistributionT: ...
@overload
def get_distribution(dist: _PkgReqType) -> Distribution: ...
def get_distribution(dist: Distribution | _PkgReqType) -> Distribution:
    """Return a current distribution object for a Requirement or string"""
    if isinstance(dist, str):
        dist = Requirement.parse(dist)
    if isinstance(dist, Requirement):
        # Bad type narrowing, dist has to be a Requirement here, so get_provider has to return Distribution
        dist = get_provider(dist)  # type: ignore[assignment]
    if not isinstance(dist, Distribution):
        raise TypeError("Expected str, Requirement, or Distribution", dist)
    return dist


def load_entry_point(dist: _EPDistType, group: str, name: str) -> _ResolvedEntryPoint:
    """Return `name` entry point of `group` for `dist` or raise ImportError"""
    return get_distribution(dist).load_entry_point(group, name)


@overload
def get_entry_map(
    dist: _EPDistType, group: None = None
) -> dict[str, dict[str, EntryPoint]]: ...
@overload
def get_entry_map(dist: _EPDistType, group: str) -> dict[str, EntryPoint]: ...
def get_entry_map(dist: _EPDistType, group: str | None = None):
    """Return the entry point map for `group`, or the full entry map"""
    return get_distribution(dist).get_entry_map(group)

View on GitHub (pinned to d7d0d0a394)

Solutions

  1. Pass a Distribution you already hold, or pass a project name string (e.g. 'requests') rather than an importable module dotted-path, so Requirement parsing + working_set lookup succeeds.
  2. Reinstall the target project with proper metadata (pip install -e . or pip install <pkg>) so an .egg-info/.dist-info directory exists and get_provider returns a Distribution.
  3. Catch TypeError around get_distribution and fall back to importlib.metadata.metadata() or importlib.metadata.distribution() for lookups.

Example fix

// before
import pkg_resources
dist = pkg_resources.get_distribution("my_namespace.sub")  # TypeError if not a real dist

// after
from importlib import metadata
dist = metadata.distribution("my-namespace-sub")  # works for installed dist metadata
Defensive patterns

Strategy: type-guard

Validate before calling

import pkg_resources
from pkg_resources import Distribution, Requirement

def safe_get_distribution(dist):
    if isinstance(dist, Distribution):
        return dist
    if isinstance(dist, str):
        # pass project name, not a dotted module path
        return pkg_resources.get_distribution(dist)
    if isinstance(dist, Requirement):
        return pkg_resources.get_distribution(dist)
    raise TypeError('pass a str project name, Requirement, or Distribution')

Type guard

from pkg_resources import Distribution, Requirement

def is_distribution_input(x):
    return isinstance(x, (str, Requirement, Distribution))

Try / catch

try:
    dist = pkg_resources.get_distribution(target)
except TypeError as e:
    if 'Expected str, Requirement, or Distribution' in str(e):
        # fall back to importlib.metadata for code-only modules
        from importlib import metadata
        dist = metadata.distribution(target)
    else:
        raise

Prevention

When it happens

Trigger: Calling pkg_resources.get_distribution('some.module') where 'some.module' is importable as code but is not backed by installed dist metadata (e.g. a namespace package, a module added to sys.path directly, a PEP 660 editable install without proper metadata, or a module whose loader type was only registered with a plain provider). Also when passing a Distribution subclass instance whose type is not recognized by get_provider's registry.

Common situations: Querying metadata for a project installed in development/editable mode without a proper .egg-info/.dist-info, a namespace package, or a module living in a flat directory on sys.path. Also after a partially-failed uninstall that left code but removed metadata.

Related errors


AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04). Data as JSON: /data/errors/a68ca9a42b3edc94.json. Report an issue: GitHub.