Hello,
we have a file provider based macOS app. Around June we started receiving reports that our users have problems when opening files. Sometimes they get "Invalid argument" alerts
after double-clicking on a dataless file. We receive similar errors when trying to materialize the files programmatically from our app (not FP extension)(*):
"The operation could not be completed. Invalid argument"
code: 22
domain: "NSPOSIXErrorDomain"
underlyingError:
"cannotMaterialize"
code: 33
domain: "libfssync.VFSFileError"
We also see those errors with matching timestamps in the output from fileproviderctl dump
:
> (...) update-item: 🔶 last:(...) (-1min27s) (...) error:'NSError: POSIX 22 "The operation couldn’t be completed. Invalid argument" Underlying={NSError: libfssync.VFSFileError 33 "cannotMaterialize" }}' domain:none category:<nil> (...)
At the same time our file provider extension receives fetchPartialContents
call or no call at all. If it receives the call it finishes with success and returns correct range:
requestedRange: "{0, 15295}"
returnedRange: "{0, 524288}"
alignment: "16384"
Sadly we don't know how to reproduce those issues. We will be grateful for any hints that could be useful in debugging.
Some more context:
- if materializing a file fails with this error, subsequent materialization attempts fail similarly
- in local testing when downloading a file with the code below, or double-click, we only get regular
fetchContents
call - file returned by
fetchPartialContents
should have correct size - the app is built with XCode 16.1, customers reporting this issue have OS/FP versions: 24F74/2882.120.74 and 24G90/2882.140.30
(*) More or less the code that we use to materialize files
func materializeURL(_ url: URL) throws {
if try url.isDataless() {
var error: NSError? = nil
let coordinator = NSFileCoordinator(filePresenter: nil)
coordinator.coordinate(readingItemAt: url, error: &error) { _ in }
if let error {
throw error
}
}
}
private extension URL {
func isDataless() throws -> Bool {
let downloadStatus = try self
.resourceValues(forKeys: [.ubiquitousItemDownloadingStatusKey])
.ubiquitousItemDownloadingStatus
return downloadStatus == .notDownloaded || downloadStatus == .none
}
}