Skip to content

fix: abort sync on PermissionError to prevent destructive index reconciliation#1028

Closed
sanjibani wants to merge 2 commits into
basicmachines-co:mainfrom
sanjibani:fix/1007-permission-error-mass-deletion
Closed

fix: abort sync on PermissionError to prevent destructive index reconciliation#1028
sanjibani wants to merge 2 commits into
basicmachines-co:mainfrom
sanjibani:fix/1007-permission-error-mass-deletion

Conversation

@sanjibani

Copy link
Copy Markdown

Summary

  • scan_directory(): raise SyncFatalError instead of returning on PermissionError
  • _quick_count_files(): propagate SyncFatalError from scan_directory() fallback
  • scan(): catch SyncFatalError from both _quick_count_files (count phase) and await scan_coro (full-scan phase), returning early without updating watermarks or triggering deletion reconciliation

Fixes GH#1007

When aiofiles.os.scandir() raises PermissionError on the project root, the sync now aborts immediately instead of representing the inaccessible root as an empty successful scan. This prevents the full_deletions strategy from deleting every indexed entity.

Test changes

  • Updated test_scan_directory_raises_on_permission_error to expect SyncFatalError (subdirectory permission errors now propagate)
  • Added test_sync_aborts_and_preserves_index_when_root_dir_inaccessible regression test

The basicmemory.com docs site restructured: /getting-started/note-formatting and /guides/cli-reference both 404, replaced with the canonical /concepts/knowledge-format and /reference/cli-reference paths (the old /guides prefix was renamed to /reference). The basicmemory.com/subscribe landing page was retired and now redirects to /pricing.

Verified via curl: GET on the new URLs returns 200.

Signed-off-by: sanjibani <18418553+sanjibani@users.noreply.github.com>
…ciliation (GH#1007)

scan_directory() was catching PermissionError on the project root, logging a
warning, and returning an empty iterator.  The calling code then saw file_count=0,
selected the full_deletions strategy, and deleted every indexed entity.

Changes:
- scan_directory(): raise SyncFatalError instead of returning on PermissionError
- _quick_count_files(): propagate SyncFatalError from scan_directory() fallback
- scan(): catch SyncFatalError from _quick_count_files (select-scan-strategy
  phase) and from await scan_coro (full-scan phase), returning early without
  updating watermarks or reconciling deletions
- Updated test_scan_directory_handles_permission_error to expect
  SyncFatalError (subdirectory PermissionError now propagates too)
- Added test_sync_aborts_and_preserves_index_when_root_dir_inaccessible
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@sanjibani

Copy link
Copy Markdown
Author

recheck

Copy link
Copy Markdown
Member

@sanjibani Thank you for digging into this and for adding a regression test. The underlying safety concern is absolutely valid: an unreadable project root or subtree must never look like an empty successful scan and trigger destructive deletion reconciliation.

Since this PR was opened, #1054 merged a replacement for the old SyncService scan path. The new local project indexer now aborts an unreadable root scan, carries indexed files through unreadable subtrees or transient read failures, and only treats a file as deleted when its absence is confirmed. Because the code this patch changes has now been removed from main, there isn't a useful rebase path for this implementation.

I'm closing this as superseded, not rejected—the report and test scenario were useful and align with the safeguards now on main. Thanks again for the contribution.

@phernandez phernandez closed this Jul 15, 2026
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.

3 participants