Visitar URL original
fix(file-provider): drop a row whose folder is gone from the server by juliusvaart · Pull Request #11025 · nextcloud/desktop · GitHub
Skip to content

fix(file-provider): drop a row whose folder is gone from the server - #11025

Open
juliusvaart wants to merge 1 commit into
nextcloud:masterfrom
juliusvaart:macos/vf/orphaned-parent-deletion
Open

juliusvaart wants to merge 1 commit into
nextcloud:masterfrom
juliusvaart:macos/vf/orphaned-parent-deletion

Conversation

@juliusvaart

@juliusvaart juliusvaart commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Resolves

No issue filed. Found while testing on a live account.

Summary

A metadata row whose parent folder no longer exists on the server is never cleaned up.

On the test account, four .indd files had rows under …/2026_Kaarten/Ontwerp/, a folder that no longer existed at that path on the server. As it turned out, it had been moved to 02_DESIGN/oud, files included. Nothing removed or corrected those rows:

  • the working-set scan does not reach them, because they are not materialised;
  • no depth-1 read of the vanished folder can report them as deleted, because the folder is gone.

Every lookup of such an item goes through parentItemIdentifierWithRemoteFallback, reads the folder, gets 404, and fails again. In practice that means a burst of errors per item on each framework cache refresh after an update:

error Could not get item parent directory item metadata for metadata.  15081073…
error Read of URL did fail.  …/2026_Kaarten/Ontwerp  errorCode 404
error Could not retrieve parent item identifier remotely.  15081073…
error Not modifying item because it was not found.  15081073…

At the first such refresh macOS also answered requestModification with "the file does not exist". The system had never known these items; they only lived in the database.

The fix

When the parent read returns 404 and the item is not materialised (not a downloaded file, not a visited folder), the row is marked deleted. Nothing can exist below a folder the server no longer has.

  • Materialised items are left alone. The working-set scan already handles them. Acting on them here could race a rename of their folder that the database has not seen yet, and drop a downloaded file.
  • Any other failure leaves the row alone, for example a 503.
  • If the item has in fact moved, its next read restores the row by its identifier.

The change is 8 lines in FilesDatabaseManager.parentItemIdentifierWithRemoteFallback.

Tests

New ParentRemoteFallbackTests:

  • testARowWhoseFolderIsGoneFromTheServerIsMarkedDeleted: the regression test. It fails without the fix and passes with it.
  • testADownloadedFileIsLeftToTheScan, testAVisitedFolderIsLeftToTheScan, testAnotherReadFailureLeavesTheRowAlone, testAFolderThatStillExistsResolvesWithoutTouchingTheRow: guards. They pass both before and after.

Full suite, run locally with swift test:

  • 394 XCTest (6 skipped, 0 failures) and 195 swift-testing tests, on master 3527955c09.
  • The first run hit two of the known timing-flaky EnumeratorTests cases, and swift-testing runs occasionally crash in swiftpm-testing-helper. Both also happen on unmodified master. The reruns were clean.
  • swiftformat --lint . is clean.

The same commit also applies and passes on top of #11004 (GRDB), once the test's initializer call gets try.

Moved rather than deleted

In the case above the files had moved, not gone. Later, a system-initiated re-listing (fileproviderd stream reset) read 02_DESIGN/oud and corrected all four rows by their identifiers. With this change the rows would have been marked deleted in between, and then restored by that same read: rows are matched by identifier, and the server payload carries deleted = false. Because these items were neither downloaded nor known to the system, nothing visible changes in between.

Not verified

  • That deleting these rows makes the burst disappear on the next update in the running app. The test covers the database behaviour, not the framework refresh. On the test account the rows had already been corrected by the re-listing before this build ran.

Checklist

AI (if applicable)

The code, tests and this description were written by Claude Code (Claude Opus 5.5) at my request, from a diagnosis of my own account's logs and database.

🤖 Generated with Claude Code

@github-actions

Copy link
Copy Markdown
Contributor

Hello there,
Thank you so much for taking the time and effort to create a pull request to our Nextcloud project.

We hope that the review process is going smooth and is helpful for you. We want to ensure your pull request is reviewed to your satisfaction. If you have a moment, our community management team would very much appreciate your feedback on your experience with this PR review process.

Your feedback is valuable to us as we continuously strive to improve our community developer experience. Please take a moment to complete our short survey by clicking on the following link: https://cloud.nextcloud.com/apps/forms/s/i9Ago4EQRZ7TWxjfmeEpPkf6

Thank you for contributing to Nextcloud and we hope to hear from you soon!

(If you believe you should not receive this message, you can add yourself to the blocklist.)

@camilasan camilasan added this to the 35.0.2 milestone Oct 27, 2026
@nilsding nilsding modified the milestones: 35.0.2, 35.0.3 Oct 30, 2026
A metadata row whose parent folder no longer exists on the server was
never cleaned up. The working-set scan does not reach it when the item
is not materialised, and no depth-1 read of the vanished folder will
ever report it as deleted. Every lookup of the item fell through to
parentItemIdentifierWithRemoteFallback, read the folder, got 404 and
failed again, for example once per item on each framework cache
refresh after an update ("Not modifying item because it was not
found.").

When that read returns 404 and the item is not materialised, mark the
row deleted. Nothing can exist below a folder the server no longer has.
Materialised items are left to the working-set scan, which already
handles them, so a rename of their folder still in flight cannot drop a
downloaded file. Any other read failure leaves the row alone. If the
item has in fact moved, its next read restores the row by its
identifier.

Assisted-by: ClaudeCode:claude-opus-5-5
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Julius van der Vaart <julius@vanderva.art>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

macOS File Provider: orphaned metadata of remotely deleted/moved folders is never purged, causing endless 404 parent lookups

3 participants