pypa/pip · error · InstallationError
Directory {name!r} is not installable. Neither 'setup.py' no
Error message
Directory {name!r} is not installable. Neither 'setup.py' nor 'pyproject.toml' found. What it means
Raised by _get_url_from_path() when the path passed to install_req_from_line looks like a path and resolves to a directory, but is_installable_dir() returns False — meaning the directory lacks both setup.py and pyproject.toml. pip will not treat a metadata-less directory as an installable project (constructors.py:315).
Source
Thrown at src/pip/_internal/req/constructors.py:315
return True
return False
def _get_url_from_path(path: str, name: str) -> str | None:
"""
First, it checks whether a provided path is an installable directory. If it
is, returns the path.
If false, check if the path is an archive file (such as a .whl).
The function checks if the path is a file. If false, if the path has
an @, it will treat it as a PEP 440 URL requirement and return the path.
"""
if _looks_like_path(name) and os.path.isdir(path):
if is_installable_dir(path):
return path_to_url(path)
# TODO: The is_installable_dir test here might not be necessary
# now that it is done in load_pyproject_toml too.
raise InstallationError(
f"Directory {name!r} is not installable. Neither 'setup.py' "
"nor 'pyproject.toml' found."
)
if not is_archive_file(path):
return None
if os.path.isfile(path):
return path_to_url(path)
urlreq_parts = name.split("@", 1)
if len(urlreq_parts) >= 2 and not _looks_like_path(urlreq_parts[0]):
# If the path contains '@' and the part before it does not look
# like a path, try to treat it as a PEP 440 URL req instead.
return None
logger.warning(
"Requirement %r looks like a filename, but the file does not exist",
name,
)
return path_to_url(path)
View on GitHub (pinned to d7d0d0a394)
Solutions
- Confirm the target directory contains pyproject.toml or setup.py: `ls <dir>`.
- Point pip at the directory that actually holds the project metadata (often one level up or down).
- If the project is elsewhere, pass the correct absolute path.
- If you intended to install a package by name from PyPI, remove the path prefix and use the distribution name instead.
Example fix
# before pip install ./docs # after pip install ./pkg
Defensive patterns
Strategy: validation
Validate before calling
import os
from pip._internal.utils.misc import is_installable_dir
def assert_dir_installable(path: str) -> None:
if os.path.isdir(path) and not is_installable_dir(path):
raise ValueError(
f"{path!r} is a directory but lacks setup.py and pyproject.toml"
) Type guard
import os
def dir_has_project_metadata(path: str) -> bool:
return os.path.exists(os.path.join(path, "pyproject.toml")) or \
os.path.exists(os.path.join(path, "setup.py")) Try / catch
null
Prevention
- Before `pip install ./dir`, confirm the dir has pyproject.toml or setup.py.
- Avoid pointing pip at documentation, test, or build-output directories.
- Use `pip show` or directory listing to verify project roots in monorepos.
When it happens
Trigger: Running `pip install ./some_dir` where some_dir exists and is a directory but contains neither setup.py nor pyproject.toml. Distinct from error 120 (which fires later in load_pyproject_toml); this one fires earlier during path-based requirement parsing.
Common situations: Pointing at a documentation/ or tests/ directory by mistake. A monorepo where the installable package is nested deeper. An empty scaffold directory created by a generator that was never populated.
Related errors
- {req_name} does not appear to be a Python project: neither '
- missing-pyproject-build-system-requires
- {editable_req} is not a valid editable requirement. It shoul
- Editable requirements are not allowed as constraints
- Invalid requirement: {req_as_string!r}: {exc}
AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04).
Data as JSON: /data/errors/8ea6b09fd2b67472.json.
Report an issue: GitHub.