dotnet/runtime · error · RuntimeError

Comparison failed for the following files(s)

Error message

Comparison failed for the following files(s): {}

What it means

Raised by update_directory() in utilities.py at src/coreclr/scripts/utilities.py:96 when filecmp.cmpfiles reports a non-empty errors list — files present in both source and destination that could not be compared due to an OS-level error (permission denied, file vanished mid-comparison, etc.).

Solutions

  1. Ensure the process has read access to all common files in srcpath and dstpath.
  2. Stop concurrent processes that may lock or delete files during the sync.
  3. Retry — a file may have been transiently locked.
  4. On Windows, exclude the directories from antivirus on-access scanning.
Defensive patterns

Strategy: retry

Validate before calling

import os, stat
for d in (srcpath, dstpath):
    for entry in os.listdir(d):
        p = os.path.join(d, entry)
        if os.path.isfile(p) and not os.access(p, os.R_OK):
            raise SystemExit(f'Unreadable file before sync: {p}')

Try / catch

for attempt in range(3):
    try:
        update_directory(srcpath, dstpath, recursive=True, destructive=True, shallow=False)
        break
    except RuntimeError as e:
        if 'Comparison failed' in str(e) and attempt < 2:
            time.sleep(2)
            continue
        raise

Prevention

When it happens

Trigger: A file exists in both srcpath and dstpath but cmpfiles fails to read/stat it; locked files on Windows; files deleted by another process during the sync.

Common situations: Antivirus locking files on Windows Helix; a concurrent process writing to dstpath; permission mismatch between source and destination.

Related errors


AI-assisted analysis of dotnet/runtime@60108ba66e (2026-08-10). Data as JSON: /api/errors/64e340a84c1c0cbd. Report an issue: GitHub.

Appendix: source

Thrown at src/coreclr/scripts/utilities.py:96

    """Updates dest directory with files from src directory

    Args:
        destpath (str): The destination path to sync with the source
        srcpath (str): The source path to sync to the destination
        recursive(boolean): If True, descend into and update subdirectories (default: True)
        destructive(boolean): If True, delete files in the destination which do not exist in the source (default: True)
        shallow(boolean): If True, only use os.stat to diff files. Do not examine contents (default: False)
    """
    srcfiles, srcdirs = split_entries(os.listdir(srcpath), srcpath)
    dstfiles, dstdirs = split_entries(os.listdir(dstpath), dstpath)


    # Update files in both src and destination which are different in destination
    commonfiles = srcfiles.intersection(dstfiles)
    _, mismatches, errors = filecmp.cmpfiles(srcpath, dstpath, commonfiles, shallow=shallow)

    if errors:
        raise RuntimeError("Comparison failed for the following files(s): {}".format(errors))

    for mismatch in mismatches:
        shutil.copyfile(os.path.join(srcpath, mismatch), os.path.join(dstpath, mismatch))

    # Copy over files from source which do not exist in the destination
    for missingfile in srcfiles.difference(dstfiles):
        shutil.copyfile(os.path.join(srcpath, missingfile), os.path.join(dstpath, missingfile))

    #If destructive, delete files in destination which do not exist in sourc
    if destructive:
        for deadfile in dstfiles.difference(srcfiles):
            print(deadfile)
            os.remove(os.path.join(dstpath, deadfile))

        for deaddir in dstdirs.difference(srcdirs):
            print(deaddir)
            shutil.rmtree(os.path.join(dstpath, deaddir))

View on GitHub (pinned to 60108ba66e)