Skip to content

fix: keep cache info of removed files when another file cannot be deleted - #541

Merged
rickdijk merged 2 commits into
Baseflow:mainfrom
junsworth:fix/await-file-removal-before-cache-info
Oct 30, 2026
Merged

rickdijk merged 2 commits into
Baseflow:mainfrom
junsworth:fix/await-file-removal-before-cache-info

Conversation

@junsworth

@junsworth junsworth commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

✨ What kind of change does this PR introduce? (Bug fix, feature, docs update...)

Bug fix.

⤵️ What is the current behavior?

If a cached file can't be deleted (for example a file locked on Windows), Future.wait throws and deleteAll is skipped for the whole batch. getOldObjects and getObjectsOverCapacity return at most 100 rows each, so one file that stays undeletable makes every cleanup reselect the same rows and stop there. emptyCache has the same all-or-nothing behavior.

🆕 What is the new behavior (if this is a feature change)?

_removeCachedFile only marks a file for cache-info deletion once the file is gone or confirmed missing. Cleanup, emptyCache and removeCachedFile then delete the cache info of every removed file and keep only the failed file's cache info, so the next cleanup retries it. The file error is still reported, and if deleteAll also fails that is logged instead of replacing it.

💥 Does this PR introduce a breaking change?

No.

🐛 Recommendations for testing

New tests in cache_store_test.dart cover a failed removal during cleanup, a failed removal in emptyCache, and the file error not being masked when deleteAll also fails. The ordering test ("should not remove cache info before the cached file is removed") already passes on main since #542, I kept it as a regression guard.

flutter test, dart format --set-exit-if-changed . and flutter analyze pass locally on Flutter 3.47.4. I haven't built the example apps locally, CI does that.

📝 Links to relevant issues/docs

Follows up on #542, which already fixed the ordering of file removal and cache-info deletion. Related: #535.

🤔 Checklist before submitting

  • All projects build
  • Follows style guide lines (code style guide)
  • Relevant documentation was updated
  • Rebased onto current main
  • Version bumped and dated CHANGELOG entry added

…info

The cleanup started removing files without waiting and then deleted the
cache info right away, so the cache info could be gone while the files
were still on disk. If the app was killed in between, those files were
left with nothing referencing them.

The cleanup now waits for the file removals first. The cache info of a
file that could not be removed is kept, so the next cleanup retries it.
@junsworth
junsworth force-pushed the fix/await-file-removal-before-cache-info branch from 3d58574 to 519ad8b Compare October 28, 2026 11:02
@junsworth

junsworth commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor Author

Hey @rickdijk ,

Please could you confirm that the following pull request #542 fixes the issue presented here in this pull request? I believe it does so thank you 🙏

I do have data to back up the orphaned files scenario that we are seeing and before closing this pull request I would like to confirm that this issue is fixed please.

Please could you confirm this?

Thanks

@rickdijk rickdijk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the detailed write-up, @junsworth. To answer your question first: yes, #542 (released in 3.4.6) already fixes the ordering problem this PR describes. On current main, _cleanupCache awaits Future.wait(futures) before provider.deleteAll(toRemove), so if the app is killed between the two steps you get a row without a file, not a file without a row. Your branch is based on that commit.

Does it fix something? Not the headline bug, since that is already fixed. There is still one real improvement, though. On main, if a single file can't be deleted (for example a file locked on Windows), Future.wait throws and deleteAll is skipped for the whole batch. getOldObjects and getObjectsOverCapacity return at most 100 rows each, so one file that stays undeletable makes every cleanup reselect the same rows and stop there. Keeping only the failed row and deleting the rest fixes that.

Does it add value? Yes, but only the partial-failure part. The title, description and CHANGELOG should describe that change rather than the ordering fix.

Tests: The second test (should keep cache info of a file that cannot be removed) covers the actual change and fails on main. On main it fails because deleteAll is never called, not because the call includes id 2. The first test already passes on main since #542. It's fine to keep as a regression guard, but it doesn't verify this PR.

Breaking change? No. There are no API changes, and the only behavior change is in the failure path.

Contribution guidelines: The template is filled in, there's one package, and the version is bumped with a dated entry. Some of the text is out of date: the description still says both PRs bump to 3.4.6 and that both tests fail on current main, and the CHANGELOG entry credits 3.4.7 with a fix that 3.4.6 already shipped. "All projects build" is left unchecked, so CI will settle that.

I've left inline comments on the details.

Comment thread flutter_cache_manager/CHANGELOG.md Resolved
Move the partial-failure handling into _removeCachedFile so cleanup,
emptyCache and removeCachedFile all delete the cache info of removed files
and keep only the failed one. A failing deleteAll is logged instead of
replacing the file removal error.
@junsworth

Copy link
Copy Markdown
Contributor Author

Thanks a lot for the thorough review, @rickdijk, and for confirming #542 covers the ordering problem. That makes sense, my branch was just based on a point before it landed. I've reworked this PR around the partial-failure part you described: the title, description and CHANGELOG now say that, and I used your suggested CHANGELOG wording. I've also moved the fix into _removeCachedFile as you suggested, so emptyCache and removeCachedFile get it too. Details are in the inline replies.

@junsworth junsworth changed the title fix: wait for cached files to be removed before deleting their cache info fix: keep cache info of removed files when another file cannot be deleted Oct 30, 2026

@rickdijk rickdijk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait for the CI to finish, then it can be merged

@rickdijk
rickdijk enabled auto-merge (squash) October 30, 2026 11:28
@rickdijk
rickdijk merged commit 0bcbec5 into Baseflow:main Oct 30, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants