pypa/pip · error · DistlibException

file '%r' does not exist

Error message

file '%r' does not exist

What it means

Raised as DistlibException by FileOperator.newer when the source file passed to it does not exist on disk. newer() compares mtimes of source and target to decide whether to copy; if the source is missing it cannot proceed. Note the message uses an extra %r inside already-quoted string, so the absolute path appears with repr-style quotes (a minor formatting quirk in the vendored code).

Solutions

  1. Check os.path.exists(source) before calling newer().
  2. Verify the upstream step that should create the source file actually ran.
  3. Wrap the call in try/except DistlibException and log/skip with context.

Example fix

# before
if fileop.newer(src, dst):
    ...
# after
if os.path.exists(src) and fileop.newer(src, dst):
    ...
Defensive patterns

Strategy: validation

Validate before calling

def newer_safe(fileop, source, target):
    if not os.path.exists(source):
        raise FileNotFoundError(source)
    return fileop.newer(source, target)

Type guard

def file_exists(path: str) -> bool:
    return isinstance(path, str) and os.path.exists(path)

Try / catch

from distlib.util import DistlibException
try:
    fileop.newer(src, dst)
except DistlibException as e:
    if 'does not exist' in str(e):
        log.warning('source missing: %s', src)

Prevention

When it happens

Trigger: Calling FileOperator().newer('/missing/src.txt', '/dest/src.txt') when /missing/src.txt does not exist; installation/unarchive flows where the source path was computed but not yet materialized; race where source is removed between scheduling and the newer() call.

Common situations: Broken install records pointing at files deleted by another tool; build pipelines that assume an earlier step produced a file that actually failed; typo in source path.

Related errors


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

Appendix: source

Thrown at src/pip/_vendor/distlib/util.py:515

    def record_as_written(self, path):
        if self.record:
            self.files_written.add(path)

    def newer(self, source, target):
        """Tell if the target is newer than the source.

        Returns true if 'source' exists and is more recently modified than
        'target', or if 'source' exists and 'target' doesn't.

        Returns false if both exist and 'target' is the same age or younger
        than 'source'. Raise PackagingFileError if 'source' does not exist.

        Note that this test is not very accurate: files created in the same
        second will have the same "age".
        """
        if not os.path.exists(source):
            raise DistlibException("file '%r' does not exist" % os.path.abspath(source))
        if not os.path.exists(target):
            return True

        return os.stat(source).st_mtime > os.stat(target).st_mtime

    def copy_file(self, infile, outfile, check=True):
        """Copy a file respecting dry-run and force flags.
        """
        self.ensure_dir(os.path.dirname(outfile))
        logger.info('Copying %s to %s', infile, outfile)
        if not self.dry_run:
            msg = None
            if check:
                if os.path.islink(outfile):
                    msg = '%s is a symlink' % outfile
                elif os.path.exists(outfile) and not os.path.isfile(outfile):
                    msg = '%s is a non-regular file' % outfile
            if msg:

View on GitHub (pinned to f399c37189)