pypa/pip · error · TypeError
Not a package:
Error message
Not a package:
What it means
Raised as TypeError inside _handle_ns when an existing sys.modules entry for packageName lacks __path__. Namespace packages require __path__ (a package marker); a plain module only has __file__. The code at line 2461 checks `not hasattr(module, '__path__')` and raises, meaning the name was already imported as a non-package module.
Solutions
- Ensure the name being declared as a namespace package is not also defined as a single-file module (.py) on sys.path.
- If the module was imported prematurely, restructure so the namespace declaration happens before any sub-imports.
- Migrate from pkg_resources.declare_namespace to PEP 420 implicit namespace packages (remove __init__.py from namespace dirs).
- Search sys.path for a conflicting module file with the same name and remove or rename it.
Example fix
// before: foo.py exists AND declare_namespace('foo') is called
import foo # imports foo.py as a module
from pkg_resources import declare_namespace
declare_namespace('foo') # TypeError: Not a package
// after: remove foo.py, make foo/ a directory without __init__.py (PEP 420)
// or ensure foo/ has __init__.py with declare_namespace before any import of foo Defensive patterns
Strategy: validation
Validate before calling
import sys
def is_namespace_safe(name: str) -> bool:
mod = sys.modules.get(name)
if mod is not None and not hasattr(mod, '__path__'):
return False # exists as a module, not a package
return True Type guard
import types
def is_package(name: str) -> bool:
mod = sys.modules.get(name)
return mod is not None and isinstance(getattr(mod, '__path__', None), list)
Try / catch
from pkg_resources import declare_namespace
try:
declare_namespace('foo')
except TypeError:
# name conflicts with an existing module; restructure packages
pass
Prevention
- Avoid name collisions between modules and namespace packages.
- Migrate to PEP 420 implicit namespace packages instead of declare_namespace.
- Check sys.modules for conflicts before declaring a namespace.
When it happens
Trigger: Calling fixup_namespace_packages() or declaring a namespace where a module with the same name was already imported as a regular module (not a package). This happens in _handle_ns at line 2462 when iterating sys.path items for namespace package registration.
Common situations: A name conflict where both a module file (e.g. foo.py) and a namespace package declaration exist for the same name; importing a single-file module before declaring it as a namespace package; mixing implicit PEP 420 namespace packages with legacy declare_namespace calls.
Related errors
- Could not find adapter for
- Entry point %r not found
- {exc}
- `base` parameter in `_fn` is `None`. Either override this…
- Can't add %r to environment
AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08).
Data as JSON: /api/errors/14186d830e5e50b0.
Report an issue: GitHub.
Appendix: 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 f399c37189)