nextcloud / nextcloud/desktop

macOS VFS: FileProviderExt crash loop (__FILEPROVIDER_BAD_ITEM_MISSING_IDENTIFIER__) — 405 on folder create embeds DB-derived collision item without identifier; corrupt records then crash change enumeration

Open
#10,701 0 comments 0 reactions 1 assignee Claimed by @camilasan View on GitHub
feature: :file_folder: file provider os: :apple: macOS
Dominant language
C++
Stars
3.9k
Forks
1k
Avg merge
1d 17h
Merged PRs (30d)
123

Description

### Bug description

On macOS with virtual files (File Provider), `FileProviderExt` enters a **crash loop**: the FileProvider framework aborts the extension with `__FILEPROVIDER_BAD_ITEM_MISSING_IDENTIFIER__` (SIGABRT). Once triggered, the loop is self-sustaining and the domain silently stops syncing.

The trigger chain, reconstructed from crash reports, the extension's JSONL logs and the `NextcloudFileProviderKit` sources (also vendored in this repo):

1. Bulk-adding a folder tree into the CloudStorage domain leads to a first extension crash mid-`createItem`. The MKCOL had already succeeded server-side, but the extension died before recording the new folder in its local (Realm) database.
2. On retry, MKCOL returns **`405 — The resource you tried to create already exists`**.
3. `NKError.fileProviderError(handlingCollisionAgainstItemInRemotePath:dbManager:remoteInterface:log:)` maps this to `NSFileProviderError(.filenameCollision)` and builds the **embedded "existing item" from the local database** (`itemMetadata(account:locatedAtRemoteUrl:)` → `Item.storedItem(...)`) — **not** from a fresh server PROPFIND. Since the DB has no (or an incomplete) record for that path — precisely what step 1 left behind — the embedded item ends up **without an itemIdentifier**.
4. macOS unwraps the embedded item (`itemFromVendorItem:`) and aborts the extension.
5. The same crash windows leave records with an empty `ocId` in the Realm DB; afterwards **every change-enumeration batch containing such a record crashes the extension too** (`FPXChangesObserver didUpdateItems:` path), so the loop persists even with no pending user operations, across reboots/days.

Two aggravating client bugs make recovery impossible without manual intervention:

- **Credentials are not re-pushed after an extension crash.** The relaunched `FileProviderExt` stays unauthenticated (all ops fail with `NSFileProviderErrorDomain -1000`, backed off by `fileproviderd`) until the desktop client app is fully restarted. Additionally, on client startup the *first* credential push contains an empty password (extension log: `Cancelling domain account setup because "password" is an empty string.`) and only a subsequent push succeeds.
- Items whose `createItem` was in flight during a crash are parked permanently by `fileproviderd` (`next:'never'`, error FP -2005), and their retries can then fail with `400 — Expected filesize of N bytes but read ... 0 bytes` (stale captured content), requiring the files to be deleted and re-created.

### Crash stacks

`createItem` error path (3 of 6 crashes):

```
FileProvider __FILEPROVIDER_BAD_ITEM_MISSING_IDENTIFIER__
FileProvider __FILEPROVIDER_BAD_ITEM__
FileProvider -[FPItem initWithVendorItem:provider:domain:spotlightDomainIdentifier:extensionCapabilities:useFPFS:]
FileProvider -[FPXDomainContext itemFromVendorItem:]
FileProvider -[NSError(FPAdditions) fp_internalErrorForVendorErrorWithCallerDescription:itemCreationBlock:]
FileProvider -[FPXDomainContext internalErrorFromVendorError:callerDescription:]
FileProvider __120-[FPXExtensionContext _createItemBasedOnTemplate:fields:contents:options:request:bounce:bounceNumber:completionHandler:]_block_invoke.641
```

Change-enumeration path (subsequent crashes, fires on every working-set signal):

```
FileProvider __FILEPROVIDER_BAD_ITEM_MISSING_IDENTIFIER__
FileProvider __FILEPROVIDER_BAD_ITEM__
FileProvider -[FPItem initWithVendorItem:provider:domain:spotlightDomainIdentifier:extensionCapabilities:useFPFS:]
FileProvider -[FPXDomainContext itemFromVendorItem:]
FileProvider -[FPXObserver updateForProviderItem:]
FileProvider -[FPXChangesObserver didUpdateItems:]
```

### Extension log excerpts (paths/hostnames redacted)

```
[error] Item: Could not create new folder at: https://cloud.example.com/remote.php/dav/files/user/ParentFolder/NewFolder,
received error: 405
The resource you tried to create already exists
```

```
[info] FileProviderExtension: Received account to configure.
[info] FileProviderExtension: Setting up domain account for user: user, userId: user, serverUrl: https://cloud.example.com, password: , ...
[info] FileProviderExtension: Cancelling domain account setup because "password" is an empty string.
```

After a database reset (attempted recovery), the split-brain state:

```
[error] Not creating item: 00024629xxxxxxxxxxxx, could not find metadata for parentItemIdentifier: 00020474xxxxxxxxxxxx
[error] Could not upload item with filename: document.pdf, received error: 400
Expected filesize of 5668673 bytes but read (from Nextcloud client) and wrote (to Nextcloud storage) 0 bytes.
```

### Steps to reproduce

Not deterministic, but reliably reproduced here twice in one day:

1. macOS client with virtual files / File Provider domain, fully synced.
2. Copy a folder tree (a few new subfolders, ~100 files) into the CloudStorage folder.
3. If the extension crashes once mid-create (for any reason), every subsequent wake crashes: retried folder creates hit 405 → collision item without identifier → abort; later, corrupted DB records crash change enumeration → abort.

### Expected behaviour

- A 405 on MKCOL should never crash the extension: fetch the colliding item's metadata from the server (PROPFIND) when it is not in the local DB, or return a plain `.filenameCollision` error without an embedded item; never hand the framework an item with an empty `itemIdentifier`.
- Enumeration observers should never be given items with empty identifiers (validate/skip corrupt DB records).
- The client should re-authenticate the extension whenever it reconnects (post-crash), not only at app start; the first credential push should not be sent with an empty password.

### Workaround that recovered the installation

Deleting only the domain's Realm DB stops the crashes but leaves the daemon/extension state inconsistent ("could not find metadata for parentItemIdentifier" on every create). Full recovery required **removing and re-creating the File Provider domain** (remove account → re-add), followed by a complete re-enumeration.

### Environment

- Desktop client: 34.0.2, auto-updated to 34.0.3 during the incident (both affected); official builds
- macOS: build 25G83, FileProvider framework 4018.160.6, Apple Silicon
- Server: Nextcloud 34.0.2.1
- Virtual files (File Provider) mode; chunked upload enabled (100 MB)

Full crash reports (`.ips`) and extension JSONL logs are available on request (they need redaction before sharing).

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.