Skip to content

Broken Symbolic Links Cause FileNotFoundError

If a broken symbolic link exists only in one directory, diffoscope fails with a FileNotFoundError.

Minimal Test Case for Reproduction

Start from any empty directory and run the following to generate the minimal test case:

mkdir my-dir-1 my-dir-2
(cd my-dir-1/ && ln -s /my-non-existent-absolute-path my-non-existent-absolute-path)

Now run diffoscope without any arguments, i.e. diffoscope my-dir-1/ my-dir-2/. Also attempted with --exclude-directory-metadata yes, appears to make no difference.

Observed Behavior

Diffoscope terminates with exit code 1 and displays the following stack trace:

Traceback (most recent call last):######################################|  100%                             ETA:  0:00:00 
  File "/usr/local/bin/diffoscope", line 8, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.8/dist-packages/diffoscope/main.py", line 746, in main
    sys.exit(run_diffoscope(parsed_args))
  File "/usr/local/lib/python3.8/dist-packages/diffoscope/main.py", line 700, in run_diffoscope
    difference = compare_root_paths(path1, path2)
  File "/usr/local/lib/python3.8/dist-packages/diffoscope/comparators/utils/compare.py", line 63, in compare_root_paths
    return compare_directories(path1, path2)
  File "/usr/local/lib/python3.8/dist-packages/diffoscope/comparators/directory.py", line 222, in compare_directories
    return FilesystemDirectory(path1).compare(FilesystemDirectory(path2))
  File "/usr/local/lib/python3.8/dist-packages/diffoscope/comparators/directory.py", line 285, in compare
    differences.extend(my_container.compare(other_container))
  File "/usr/local/lib/python3.8/dist-packages/diffoscope/comparators/utils/container.py", line 164, in comparisons
    for my_name, other_name, score in self.perform_fuzzy_matching(
  File "/usr/local/lib/python3.8/dist-packages/diffoscope/comparators/utils/fuzzy.py", line 45, in perform_fuzzy_matching
    if file1.is_directory() or not file1.fuzzy_hash:
  File "/usr/local/lib/python3.8/dist-packages/diffoscope/comparators/utils/file.py", line 342, in fuzzy_hash
    if os.stat(self.path).st_size >= 512:
FileNotFoundError: [Errno 2] No such file or directory: 'my-dir-1/my-non-existent-absolute-path'

Expected Behavior

Diffoscope should terminate normally and show the missing (from the perspective of my-dir-2) symbolic link in the file list.

This suggestion is based on the following observation: If we add an identical broken symbolic link to the second directory, i.e. by running (cd my-dir-2/ && ln -s /my-non-existent-absolute-path my-non-existent-absolute-path), diffoscope will simply report the difference of the stat calls of the symbolic links. In other words, it does not attempt to deference the links and thus does not care that they are broken.

Environment and Versions

This error occurred for us with the latest diffoscope version (177 as of writing), running python 3.8.10 on Ubuntu 20.04

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information