pypa/pip · error · TypeError

Not a package:

Error message

Not a package:

What it means

Raised as TypeError by _handle_ns(packageName, path_item): while scanning sys.path entries for a namespace package, pkg_resources found the package already present in sys.modules but that module object lacks a __path__ attribute — i.e. it is a regular single-file module, not a package. Namespace packages require __path__, so treating a plain module as a namespace root is an error.

Source

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

    try:
        spec = importer.find_spec(packageName)
    except AttributeError:
        # capture warnings due to #1111
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            loader = importer.find_module(packageName)
    else:
        loader = spec.loader if spec else None

    if loader is None:
        return None
    module = sys.modules.get(packageName)
    if module is None:
        module = sys.modules[packageName] = types.ModuleType(packageName)
        module.__path__ = []
        _set_parent_ns(packageName)
    elif not hasattr(module, '__path__'):
        raise TypeError("Not a package:", packageName)
    handler = _find_adapter(_namespace_handlers, importer)
    subpath = handler(importer, path_item, packageName, module)
    if subpath is not None:
        path = module.__path__
        path.append(subpath)
        importlib.import_module(packageName)
        _rebuild_mod_path(path, packageName, module)
    return subpath


def _rebuild_mod_path(orig_path, package_name, module: types.ModuleType):
    """
    Rebuild module.__path__ ensuring that all entries are ordered
    corresponding to their sys.path order
    """
    sys_path = [_normalize_cached(p) for p in sys.path]

    def safe_sys_path_index(entry):

View on GitHub (pinned to d7d0d0a394)

Solutions

  1. Resolve the name collision: rename the conflicting module or the namespace package so they no longer share a dotted name.
  2. Remove the stale namespace_packages.txt / __init__.py declaring the namespace if the project migrated to PEP 420 implicit namespaces.
  3. Ensure the package directory (with __path__) is imported before any same-named module is, so sys.modules holds a real package.

Example fix

// before
# project_a ships namespace_packages.txt listing 'shared' 
# project_b has a flat module shared.py
import shared          # plain module in sys.modules
pkg_resources.declare_namespace('shared')  # TypeError: Not a package

// after
# rename the flat module or make 'shared' a real package dir with __init__.py
# then declare_namespace sees a package with __path__
Defensive patterns

Strategy: validation

Validate before calling

import sys, types

def safe_namespace_name(name):
    mod = sys.modules.get(name)
    if mod is not None and not hasattr(mod, '__path__'):
        return False  # a plain module occupies this name
    return True

Type guard

import sys

def name_is_package_or_free(name) -> bool:
    mod = sys.modules.get(name)
    return mod is None or hasattr(mod, '__path__')

Try / catch

try:
    pkg_resources.fixup_namespace_packages(path_item)
except TypeError as e:
    if 'Not a package' in str(e):
        # name collision; skip or rename
        pass
    else:
        raise

Prevention

When it happens

Trigger: A call path that triggers _handle_ns for a name (e.g. via declare_namespace, fixup_namespace_packages, or Distribution.activate scanning namespace_packages.txt) where the same name is already imported as a non-package module (a .py file, not a package directory).

Common situations: Name collision: a namespace package declaration (often from a dependency's namespace_packages.txt) references a name that a different dependency already imported as a regular module. Common in monorepos or when a vendored module shadows a namespace package.

Related errors


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