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 when filecmp.cmpfiles reports files in the `errors` list — files that exist in both src and dst but could not be compared (os.error on stat/read, permission denied, etc.). The directory sync aborts rather than silently skipping.

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 290d5ab72c)

Solutions

  1. Inspect the files in the error list for locks/permissions: `ls -l` and `stat` each.
  2. Close any process holding the files (or disable AV locking) and rerun.
  3. Fix permissions: `chmod -R u+rw <dst>` (or the offending side).
  4. If a file is genuinely corrupt/unreadable, remove it from dst so update_directory copies it fresh.

Example fix

// before
# update_directory raises [197] with ['coreclr.dll']
// after
chmod u+rw <dst>/coreclr.dll  # or rm it; rerun update_directory
Defensive patterns

Strategy: validation

Validate before calling

import os, stat
for f in commonfiles:
    for side in (srcpath, dstpath):
        p = os.path.join(side, f)
        if not os.access(p, os.R_OK):
            raise SystemExit(f'{p} not readable; fix perms before update_directory')

Type guard

def all_commonfiles_readable(commonfiles, srcpath, dstpath) -> bool:
    import os
    return all(os.access(os.path.join(s,f), os.R_OK) for f in commonfiles for s in (srcpath,dstpath))

Try / catch

try:
    update_directory(src, dst)
except RuntimeError as e:
    if 'Comparison failed' in str(e):
        import re; files = re.findall(r"'([^']+)'", str(e))
        for f in files: os.chmod(os.path.join(dst,f), 0o644)
        update_directory(src, dst)

Prevention

When it happens

Trigger: A common file exists in src and dst but filecmp cannot stat or open it (EACCES, EIO, file locked on Windows, symlink loop, transient FS error).

Common situations: Windows file lock on a DLL being written; read-only permissions on dst; broken symlinks; network-mounted artifact dir with intermittent errors; antivirus locking the file mid-compare.

Related errors


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