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

  1. Use pathlib.Path(path).resolve().as_uri() to generate correct absolute file URLs
  2. Ensure the path starts with / on Unix or uses proper Windows drive format
  3. 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

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


AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08). Data as JSON: /api/errors/8948fa5784afc85b. Report an issue: GitHub.