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
- Resolve the name collision: rename the conflicting module or the namespace package so they no longer share a dotted name.
- Remove the stale namespace_packages.txt / __init__.py declaring the namespace if the project migrated to PEP 420 implicit namespaces.
- 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
- Avoid name collisions between namespace packages and regular modules.
- Migrate to PEP 420 implicit namespace packages (remove declare_namespace calls).
- Audit namespace_packages.txt in dependencies for stale entries.
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
- Can't add %r to environment
- `base` parameter in `_fn` is `None`. Either override this me
- Error decoding metadata for {self._wheel_name}: {e} in {name
- Wheel '{name}' located at {location} is invalid.
- Python 3.8 or later is required
AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04).
Data as JSON: /data/errors/14186d830e5e50b0.json.
Report an issue: GitHub.