Skip to content

Treat a vanished entry as a miss in FileTreeStore.get_entry - #367

Open
jonaseck2 wants to merge 1 commit into
strawgate:mainfrom
jonaseck2:filetree-get-enoent-is-miss
Open

Treat a vanished entry as a miss in FileTreeStore.get_entry#367
jonaseck2 wants to merge 1 commit into
strawgate:mainfrom
jonaseck2:filetree-get-enoent-is-miss

Conversation

@jonaseck2

@jonaseck2 jonaseck2 commented Aug 17, 2026

Copy link
Copy Markdown

Closes #366.

get_entry checks that the file exists and then opens it. If something deletes the entry in between, read_file raises FileNotFoundError and it reaches the caller.

This returns None instead. That is what get already returns when the file is gone at the exists() check, and what delete_entry does in the same class.

The test removes the file inside the exists() call, following test_delete_returns_false_when_file_disappears_before_unlink, so the interleaving is deterministic rather than timing-dependent.

Checks on Python 3.12: ruff format and ruff check clean, basedpyright 0 errors, and the two filetree race tests pass. Without the change in store.py the new test fails with FileNotFoundError.

Context for why this matters in practice is in #366: we hit it on FastMCP's OAuthProxy, where one-time-use refresh tokens are deleted as part of normal rotation, and the exception turned a cache miss the caller handles into an HTTP 500.

Review in cubic

get_entry checks that the file exists and then opens it. If something
deletes the entry in between, read_file raises FileNotFoundError and it
reaches the caller.

Return None instead. That is what get already returns when the file is
gone at the exists() check, and what delete_entry does in the same class.

The test removes the file inside the exists() call, following
test_delete_returns_false_when_file_disappears_before_unlink, so the
interleaving is deterministic rather than timing-dependent.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 5c8bca6e-5184-4f06-8395-7d51f7a01da7

📥 Commits

Reviewing files that changed from the base of the PR and between 5929cff and 2490ce9.

📒 Files selected for processing (2)
  • src/key_value/aio/stores/filetree/store.py
  • tests/stores/filetree/test_filetree.py

Included review availability: Your plan includes up to 1 review per rolling hour; 0 remain after this review.


Walkthrough

DiskCollectionInfo.get_entry now catches FileNotFoundError when a file is removed after the existence check. It returns None, matching the behavior for an entry that is already missing. A regression test reproduces this race and verifies that FileTreeStore.get returns None instead of propagating the exception.

Merge Risk: ⚪ Minimal · up to 2490c

This localized change treats an entry deleted during lookup as a cache miss instead of raising an error, with targeted tests and clean checks reported; no actionable merge-blocking risk remains after normal review.

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The change catches FileNotFoundError during the read and returns None, with a regression test covering deletion after exists().
Out of Scope Changes check ✅ Passed The changes are limited to the requested race-condition fix and its regression test.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No issues found across 2 files

Auto-approved: Focused bug fix: catches FileNotFoundError between exists() and read to return None, matching existing get/delete_entry miss semantics, with a deterministic race test. No design or operational tradeoff requires human judgment.

Re-trigger cubic

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.

FileTreeStore.get raises FileNotFoundError if the entry is deleted after the exists() check

1 participant