Post

Replies

Boosts

Views

Activity

Reply to Widget error upon restore iPhone: The file "Name.sqlite" couldn't be opened
Thank you, this is very helpful. To confirm we're aligned: Open the database in read-only mode If loadPersistentStores fails, try it again in read-write mode If that succeeds destroy those CoreData object and do a read-only open again If that fails show an error message to the user destroy those CoreData object Is that accomplished via container.persistentStoreCoordinator.destroyPersistentStore, so all together like so? let container = NSPersistentCloudKitContainer(name: "AppName") let sharedStoreURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.domain.appname")!.appendingPathComponent("\(container.name).sqlite") guard FileManager.default.fileExists(atPath: sharedStoreURL.path) else { // Show error to user return } let description = container.persistentStoreDescriptions.first! description.url = sharedStoreURL description.isReadOnly = true container.loadPersistentStores { description, error in if let error { container.persistentStoreDescriptions.first?.isReadOnly = false container.loadPersistentStores { description, error in if let error { // Show error to user } else { try? container.persistentStoreCoordinator.destroyPersistentStore(at: sharedStoreURL, type: .sqlite) container.persistentStoreDescriptions.first?.isReadOnly = true container.loadPersistentStores { description, error in if let error { // Show error to user } } } } } }
Jun ’25
Reply to Widget error upon restore iPhone: The file "Name.sqlite" couldn't be opened
Thanks Kevin! I captured a sysdiagnose and found this: error 2025-06-17 08:33:06.224277 -0600 MyAppWidget os_unix.c:46922: (2) open(/private/var/mobile/Containers/Shared/AppGroup/FC8E38EF-1FEF-4C9A-9712-D10421E30FE5/Name.sqlite-wal) - No such file or directory error 2025-06-17 08:33:06.224284 -0600 MyAppWidget unable to open database file in "SELECT TBL_NAME FROM SQLITE_MASTER WHERE TBL_NAME = 'Z_METADATA'" error 2025-06-17 08:33:06.224863 -0600 MyAppWidget error: (14) I/O error for database at /private/var/mobile/Containers/Shared/AppGroup/FC8E38EF-1FEF-4C9A-9712-D10421E30FE5/Name.sqlite. SQLite error code:14, 'unable to open database file' I confirmed upon restore the sqlite file exists but sqlite-wal does not - it won’t open without that file. But that file does get created once you open the app, and then you can reinitialize the widget by restarting the iPhone (that’s the only way I know to make the system cold start the widget process). You’re exactly right, setting isReadOnly is what causes this behavior. If I do not put it in read-only mode, the error does not occur because it is apparently able to open the database file without the sqlite-wal file, the same way the app is able to. So I can work around the issue by setting isReadOnly only when the sqlite-wal file exists. That means it would be in read/write mode until the user restarts the iPhone then it’ll be read-only. I’m wondering if that's a bad idea. I don’t attempt to write to the database from the widget, but the widget does not sync (cloudKitContainerOptions is not set), so are there any implications in making the widget open in read/write mode, creating the wal file in the process? If the data has been changed on iCloud and thus is out of date, would that cause the app to fail to sync or have some other effect when it's opened? 🤔 Is it expected for the sqlite-wal file to be missing after restore? It seems if that were preserved the issue would not occur (maybe the sqlite-shm file is also required, that too is missing).
Jun ’25
Reply to Widget error upon restore iPhone: The file "Name.sqlite" couldn't be opened
It's interesting huh! One option would be to simply delete the file and let CoreData pull the data from the cloud … you might want to consider just excluding the file from the backup entirely I think this is not an option because the user can turn off iCloud and NSPersistentCloudKitContainer still works to store data without syncing to iCloud. So not all users can get this data back from iCloud, it may only exist in their backup. What does your app actually "do" and, most importantly, what if any background modes/work does it use? You can think of it as a very simple "todo" app where you create a todo, it shows up in the widget, and tapping a button marks it complete (via the main app process). Note the widget's access to the database is read-only and cloudKitContainerOptions is not set so the widget extension process does not sync with iCloud (only the main app process does). The only background modes/work used in the app is the "remote notifications" capability that allows CloudKit to silently notify the app when there's new content enabling NSPersistentCloudKitContainer to do its magic - there's no additional background tasks implemented. On its own I'm not sure how restarting would have changed anything, but having your app run FIRST (before the widget did) might have changed something. Does that fit in with any of what your app is doing? I did more testing here. If I follow the steps and install the app from the App Store after restore, the widget is run and shows the error, now if you restart the iPhone again the widget is run and shows the same error. So restarting the iPhone only resolves the problem after the main app has been run. If you never open the app, the widget error never resolves. You have to open the app and then restart the device to resolve it. The only code differences I have for persistence setup in the app vs the widget is to migrate the file at the default store URL to the shared app groups URL if it hasn't been migrated yet, set cloudKitContainerOptions, and it does not set isReadOnly. Does your Widget try to setup myPersistentCloudKitContainer again at any of those points? The widget sets up the NSPersistentCloudKitContainer and calls loadPersistentStores only once upon init, which happens at the time WidgetKit calls getSnapshot, getTimeline, or relevance (whichever is called first).
Jun ’25
Reply to Widget error upon restore iPhone: The file "Name.sqlite" couldn't be opened
Hi Ziqiao Chen! It seems the URL does change after reset (but is still valid) and the URL does not change upon restarting iPhone to get the successful case. I added debug text to my widget to show the URL and whether it can be accessed, then performed these steps: Run the app on my iPhone from Xcode and verify there is no error in the widget, note the sqlite file URL Perform iCloud backup Reset iPhone and restore from that backup The app is not automatically installed because only apps downloaded from the App Store are reinstalled, so I had to enable Developer Mode then run the app from Xcode The error message appears in the widget - the sqlite file couldn't be opened, it is a different URL than it was before the iPhone was reset, and yet FileManager says the file exists, the file is readable and writable, and the contents at that path are non-nil Restart iPhone The error message is not shown in the widget and everything else is the same (the URL, file exists, readable, writable, non-nil contents) The URL in step 1 was file:///private/var/mobile/Containers/Shared/AppGroup/FAF64427-9826-4C86-9C2E-D7E5285BA7EC/MyApp.sqlite The URL in step 5 and 7 was file:///private/var/mobile/Containers/Shared/AppGroup/FDE4F3AF-E775-4D5F-842D-1C5AA77BE26F/MyApp.sqlite The URL is set like this myPersistentCloudKitContainer.persistentStoreDescriptions[0].url = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.mydomain.myapp")!.appendingPathComponent("\(container.name).sqlite"). Note if you install the app from the App Store instead of installing it via Xcode in step 4, you also see the error in the widget. But if you first delete the app and then install it, you of course wouldn't see the error since there's no existing data from the app. While this may not replicate the issue exactly, it seems to be close enough with the same end result - the app can access the database but the widget fails to until you restart iPhone. It seems it can only be fully tested with the production app that's live on the App Store, since that's the only way iOS will reinstall it upon restore from backup. I can't put debug text in my widget for customers to see. 😀
Jun ’25