Repository navigation
[tool] consider making ErrorHandlingFileSystem.deleteIfExists catch system error code ERROR_PATH_NOT_FOUND (3) on Windows #150736
Description
Discovered while investigating #137168. As of writing this, I believe that resolving this issue is prerequisite to solving that one.
Consider #137168. The crashing exception here is PathNotFoundException: PathNotFoundException: Deletion failed, path = 'D:\<project dir path>\windows\flutter\ephemeral\.plugin_symlinks' (OS Error: The system cannot find the path specified. , errno = 3). However, if we look at the code that threw this, we notice that it confirms the existence of the directory before it tries to delete it.
flutter/packages/flutter_tools/lib/src/flutter_plugins.dart
Lines 1039 to 1042 in 99c7e9f
| if (force && symlinkDirectory.existsSync()) { | |
| // Start fresh to avoid stale links. | |
| symlinkDirectory.deleteSync(recursive: true); | |
| } |
Barring some more complex bug in the tool or Dart's filesystem abstractions, this strongly suggests that something happened to this directory in the time between the tool checking for its existence and trying to delete it.
While it could be argued that this deleteSync call should be replaced a ErrorHandlingFileSystem.deleteIfExists call, this still would not be sufficient to prevent the crash, because deleteIfExists will still throw if it encounters ERROR_PATH_NOT_FOUND:
flutter/packages/flutter_tools/lib/src/base/error_handling_io.dart
Lines 75 to 87 in fda9ecf
| static bool deleteIfExists(FileSystemEntity file, {bool recursive = false}) { | |
| if (!file.existsSync()) { | |
| return false; | |
| } | |
| try { | |
| file.deleteSync(recursive: recursive); | |
| } on FileSystemException catch (err) { | |
| // Certain error codes indicate the file could not be found. It could have | |
| // been deleted by a different program while the tool was running. | |
| // if it still exists, the file likely exists on a read-only volume. | |
| if (err.osError?.errorCode != kSystemCannotFindFile || _noExitOnFailure) { | |
| rethrow; | |
| } |
Notice that if the error code is not kSystemCannotFindFile, we will rethrow. Here is the definition of this constant:
flutter/packages/flutter_tools/lib/src/base/error_handling_io.dart
Lines 24 to 26 in fda9ecf
| /// On windows this is error code 2: ERROR_FILE_NOT_FOUND, and on | |
| /// macOS/Linux it is error code 2/ENOENT: No such file or directory. | |
| const int kSystemCannotFindFile = 2; |
We should augment deleteIfExists to not rethrow in the presence of ERROR_PATH_NOT_FOUND on Windows.
Activity
andrewkolos commentedon Jun 24, 2024
This isn't an easy fix, because
ErrorHandlingFileSystem.deleteIfExistsdoes not know what the OS of the arguedFileSystemEntityis, andFileSystemEntity(correctly IMO) does not expose this. The current implementation lucks out on the fact that system code2means more or less the same thing on Windows and POSIX file systems. However, this is not the case with code3. On POSIX systems,3corresponds to "no such process."1 We could proceed with just catching3regardless since this error code is (probably?) entirely disjoint from file-system related issues. It would just be a bit of a smelly hack.I can't think of any "cleaner" ways to solve this. One way would be to modify
ErrorHandlingFileSystem.deleteIfExiststo have a requiredFileSystemStyle styleparameter, would be annoying and possibly prone to error. Another way would be to ban direct operations on theFileandDirectoryinterfaces throughout the flutter tool. Instead, tool code would operate directly only onErrorHandlingFileandErrorHandlingDirectory, which would exposedeleteIfExistsanddeleteIfExistsSyncon their parent type (would would probably be a new type we introduce).Footnotes
https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/errno-base.h#L7 ↩
[tool] make `ErrorHandlingFileSystem.deleteIfExists` catch error code…
[tool] make `ErrorHandlingFileSystem.deleteIfExists` catch error code…
[CP-stable][tool] make `ErrorHandlingFileSystem.deleteIfExists` catch…
github-actions commentedon Jul 10, 2024
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of
flutter doctor -vand a minimal reproduction of the issue.