pypa/pip · error · ValueError
Unexpected file name derived from URL
Error message
Unexpected file name derived from URL: {name!r} What it means
Raised as ValueError from as_path_component in link.py:53-63. as_path_component reduces a name to a single safe filesystem component (via os.path.basename) and is meant to reject names that would collapse to empty/./.. before writing a file. If after basename reduction the result is empty (e.g. the URL-derived name is empty, '.', '..', or only a separator), it raises ValueError because writing under such a name would be unsafe (it could escape or overwrite the target directory).
Solutions
- Ensure the source URL resolves to a concrete file name with a real basename component.
- Validate/sanitize the link's URL-derived name before passing to as_path_component.
- Report the offending URL to pip maintainers if it is a legitimate index link.
Example fix
// before: URL yields empty basename
name = '' # derived from a directory-only URL
component = as_path_component(name)
// after: guard against empty names
if not name or os.path.basename(name) in ('', '.', '..'):
raise ValueError(f'No usable file name in URL')
component = as_path_component(name) Defensive patterns
Strategy: validation
Validate before calling
// Before calling as_path_component, ensure the URL yields a real basename:
import os
base = os.path.basename(name)
if base in ('', os.curdir, os.pardir):
raise ValueError(f'URL produces no usable file name: {name!r}')
component = as_path_component(name) Try / catch
try:
component = as_path_component(name)
except ValueError:
# synthesize a safe name or reject the link
... Prevention
- Sanitize URL-derived file names before using them as path components.
- Reject directory-only or empty file-name URLs at link construction time.
- Treat basename reduction to '.'/'..' as a security-relevant failure.
When it happens
Trigger: Calling as_path_component(name) where name, after os.path.basename, is '', '.', or '..' — e.g. a Link whose URL yields an empty/relative file name component when pip derives a cache/download path.
Common situations: A malformed Link URL that produces no usable file name (trailing slash, directory-only URL, drive-letter-only on Windows); a crafted/edge-case URL that basename reduces to '.' or '..'; a bug in URL-to-filename derivation.
Related errors
- Absolute paths are not supported in pylock files obtained…
- Path in pylock file obtained from a URL resolves outside…
- An error occurred while writing to the configuration file
- At least one hash must be provided
- `base` parameter in `_fn` is `None`. Either override this…
AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08).
Data as JSON: /api/errors/2f06be88770cc9b1.
Report an issue: GitHub.
Appendix: source
Thrown at src/pip/_internal/models/link.py:61
``os.path.basename`` drops any directory part, drive letter, or separator;
a ``.``, ``..``, or empty result is not a component and becomes ``""``.
"""
name = os.path.basename(name)
if name in ("", os.curdir, os.pardir):
return PathComponent("")
return PathComponent(name)
def as_path_component(name: str) -> PathComponent:
"""Like ``_to_path_component`` but reject the empty result.
Use where a file is about to be written, so a missing name is an error
rather than a silent fallback to the directory itself.
"""
component = _to_path_component(name)
if not component:
raise ValueError(f"Unexpected file name derived from URL: {name!r}")
return component
def join_within_directory(directory: str, component: PathComponent) -> str:
"""Join a single path ``component`` onto ``directory``.
``component`` is a :data:`PathComponent`, so by type it has no separator and
is not a ``.`` or ``..`` reference; the result can never escape ``directory``.
Requiring ``PathComponent`` rather than ``str`` lets the type checker enforce
at the call site that the name was reduced to a safe component beforehand.
"""
return os.path.join(directory, component)
# Order matters, earlier hashes have a precedence over later hashes for what
# we will pick to use.
_SUPPORTED_HASHES = ("sha512", "sha384", "sha256", "sha224", "sha1", "md5")View on GitHub (pinned to f399c37189)