fix: one unreadable path no longer stops the file cache tracking anything - #1981
Merged
rmcrackan merged 1 commit intoAug 19, 2026
Merged
Conversation
…hing All three Windows CI legs failed on master while the other six passed, and not on an assertion: every test in FileLiberator.Tests' PDF path suite failed in TestInitialize with an AggregateException wrapping FileNotFoundException, naming a path none of those tests had anything to do with. The watcher had raised Created for a folder an earlier test's cleanup then deleted. AddPath asked whether the path existed, was told yes, asked what it was, and got an exception - Exists and GetAttributes can disagree over a long \\?\ path, and the answer to the first can stop being true before the second is asked anyway. That exception ended the background scanner, so nothing further reached the cache, and it was stored on the task, so the next Stop() rethrew it as an AggregateException at whoever had called Refresh(). In the app that caller is the Books directory refresh after every download. Three changes, smallest first: the attribute read is guarded and returns 'nothing to add' where the existence check used to say it, which also removes the race rather than narrowing it; the scanner survives an event it cannot apply; and Stop() waits on a scanner that has already failed without handing the failure to a caller that is about to replace it. Co-authored-by: rmcrackan <rmcrackan@gmail.com>
rmcrackan
marked this pull request as ready for review
August 19, 2026 20:27
rmcrackan
deleted the
cursor/keep-file-cache-alive-past-a-vanished-path-a274
branch
August 19, 2026 20:31
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes the Windows CI failures on master after #1976.
What failed
All three Windows legs of run 32296036630 failed while the six Linux and macOS legs passed, and not on an assertion. Every test in
FileLiberator.Tests' PDF path suite failed inTestInitialize:The path named is one no test in that class ever creates, and the failure is in setup rather than in any assertion — the signature of process-wide state left broken by something that ran earlier.
Why
BackgroundFileSystem.AddPathasked two questions and let the second trust the first:The watcher had raised
Createdfor a folder an earlier test's cleanup then deleted.Existssaid yes andGetAttributesthrew — those two disagree over a long\\?\path, and the answer to the first can stop being true before the second is asked in any case, which is what the comment about temp files was already acknowledging.That exception cost two things, and the second is what made it look unrelated:
BackgroundScanner's loop, so nothing further reached the cache for the rest of the process.Stop()—backgroundScanner?.Wait()— rethrew it as anAggregateExceptionat whoever calledRefresh(). In the tests that wasDownloadPdfPathTests.Initialize. In the app it isAudibleFileStorage.Audio.Refresh(), which runs after every download.So a user moving or deleting a book folder while Libation is running could silently stop file tracking, and then surface as a failure attributed to their next download. This is the same class of fragility as
d27445a1andb9aa51cd, which hardened the watcher callback; this is the scanner task behind it.The fix
Three changes, smallest first:
UpdateLocalCachecan end tracking or be stored for an unrelated caller to receive.Stop()waits on a scanner that has already failed without raising that failure at a caller which is about to replace it anyway.Verification
a_path_that_is_not_there_reads_as_nothing_rather_than_throwingfails against the old code with the same exception CI produced, and passes with the fix:The trigger —
ExistsandGetAttributesdisagreeing over a long\\?\path — cannot be staged on Linux, so the guard is asserted directly and the surrounding tests cover what its failure used to cost: a cache that stops tracking new files, andDispose()handing the exception to its caller.a_path_that_is_there_still_reads_as_what_it_iskeeps the guard honest, since a guard that swallowed everything would also pass the others.1507 tests pass locally, and both the CLI and the Avalonia app build clean.