pypa/pip · error · DirectUrlValidationError
File URL must be absolute when dir_info is present
Error message
File URL must be absolute when dir_info is present
What it means
When dir_info is present and the URL scheme is file, the path component must be absolute (start with /). A relative file URL like file:relative/path is invalid because directory sources must point to an unambiguous filesystem location. If the path does not start with /, DirectUrlValidationError is raised.
Source
Thrown at src/pip/_vendor/packaging/direct_url.py:305
subdirectory=_get(d, str, "subdirectory"),
)
if (
bool(direct_url.vcs_info)
+ bool(direct_url.archive_info)
+ bool(direct_url.dir_info)
) != 1:
raise DirectUrlValidationError(
"Exactly one of vcs_info, archive_info, dir_info must be present"
)
if direct_url.dir_info is not None:
parsed_url = urllib.parse.urlsplit(direct_url.url)
if parsed_url.scheme != "file":
raise DirectUrlValidationError(
"URL scheme must be file:// when dir_info is present",
context="url",
)
if not _file_url_has_absolute_path(parsed_url):
raise DirectUrlValidationError(
"File URL must be absolute when dir_info is present",
context="url",
)
# XXX subdirectory must be relative, can we, should we validate that here?
return direct_url
@classmethod
def from_dict(cls, d: Mapping[str, Any], /) -> Self:
"""Create and validate a DirectUrl instance from a JSON dictionary."""
return cls._from_dict(d)
def to_dict(
self,
*,
generate_legacy_hash: bool = False,
strip_user_password: bool = True,
safe_user_passwords: Collection[str] = ("git",),
) -> Mapping[str, Any]:View on GitHub (pinned to f399c37189)
Solutions
- Use pathlib.Path(path).resolve().as_uri() to generate correct absolute file URLs
- Ensure the path starts with / on Unix or uses proper Windows drive format
- Fix the URL to be absolute before parsing
Example fix
# before
data = {
"url": "file:relative/path/to/project",
"dir_info": {"editable": True}
}
# after
from pathlib import Path
data = {
"url": Path("relative/path/to/project").resolve().as_uri(),
"dir_info": {"editable": True}
} Defensive patterns
Strategy: validation
Validate before calling
import urllib.parse
from pathlib import Path
def validate_file_url_absolute(data: dict) -> None:
if data.get("dir_info") is not None:
parsed = urllib.parse.urlsplit(data["url"])
if parsed.scheme == "file" and not parsed.path.startswith("/"):
raise ValueError(f"File URL must be absolute, got: {data['url']!r}")
def make_file_url(path: str) -> str:
return Path(path).resolve().as_uri() Type guard
import urllib.parse
def is_absolute_file_url(url: str) -> bool:
parsed = urllib.parse.urlsplit(url)
return parsed.scheme != "file" or parsed.path.startswith("/") Try / catch
from packaging.direct_url import DirectUrl, DirectUrlValidationError
from pathlib import Path
try:
du = DirectUrl.from_dict(data)
except DirectUrlValidationError as e:
if "must be absolute" in str(e):
raw_path = data["url"].replace("file:", "")
data["url"] = Path(raw_path).resolve().as_uri()
du = DirectUrl.from_dict(data) Prevention
- Always use Path.resolve().as_uri() for file URLs
- Never construct file:// URLs by string concatenation
- Test URL generation on Windows where path formats differ
When it happens
Trigger: Calling DirectUrl.from_dict(data) with dir_info and a file URL that has a relative path: e.g. {'url': 'file:relative/path', 'dir_info': {}}.
Common situations: Constructing file URLs manually without leading slashes on Unix or without proper drive/UNC format on Windows. Using string concatenation (file: + relative_path) instead of Path.as_uri().
Related errors
- URL scheme must be file:// when dir_info is present
- Unexpected type {type(value).__name__} (expected {expected_t
- Exactly one of vcs_info, archive_info, dir_info must be pres
- Hash values must be strings
- Invalid hash format (expected '<algorithm>=<hash>')
AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08).
Data as JSON: /api/errors/8948fa5784afc85b.
Report an issue: GitHub.