Failed to open file at path '....default.realm.lock': Operation not permitted

Hi,
I have a local realm which works great for the most part. But ever since the app is on the store, it seems sometimes the app just fails to open the realm. It’s rare, but it happens, and to the same users.

Fatal error: ‘try!’ expression unexpectedly raised an error: Error Domain=io.realm Code=3 “Failed to open file at path ‘/private/var/mobile/Containers/Shared/AppGroup/…/default.realm.lock’: Operation not permitted” UserInfo={Error Code=3, NSFilePath=/private/var/mobile/Containers/Shared/AppGroup/…/default.realm.lock, Error Name=PermissionDenied, NSLocalizedDescription=Failed to open file at path ‘/private/var/mobile/Containers/Shared/AppGroup/…/default.realm.lock’: Operation not permitted}

I noticed that when these crashes occur the deviceid for the vendor was also returning nil. Maybe it’s related. Currently it’s the highest frequency crash for my app.

Thanks!

That’s interesting. Do you have some code that replicates the issue? At what point in your app is the err being thrown? At startup or later? Are you using shouldCompactOnLaunch()?

No code to replicate the issue.
The error is happens on startup of the app, when initiating realm from the first view controller’s viewDidLoad method. I am not using shouldCompactOnLaunch. It’s worth mentioning the app is written mostly in ObjC, though the code initiating realm is in Swift.

Can you share that code? May not make a difference but we have to start somewhere.

ok this is my app startup:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
    config.schemaVersion = 1;
    NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.forcam.app"];
    NSURL *realmURL = [containerURL URLByAppendingPathComponent:@"default.realm"];
    config.fileURL = realmURL;
    NSError *error;
    [[NSFileManager defaultManager] setAttributes:@{ NSFileProtectionKey:
                                                         NSFileProtectionNone } ofItemAtPath:[realmURL absoluteString] error:&error];
    [RLMRealmConfiguration setDefaultConfiguration:config];

I added the setAttributes function because of a GitHub issue I tracked (iOS crash due to default.realm.lock': open() failed: Operation not permitted Path · Issue #7874 · realm/realm-swift · GitHub) that I thought could help.

Then in the viewDidLoad of the main app view controller I called:

    @objc static func getAllFavorited(sortedBy sortOption: FavoriteSort = .unsorted) -> [Models] {
        let realm = try! Realm()

and it crashes here.

Realm creates/destroys a few files in the same directory as the .realm file on the fly and it looks like the only file that has full permission is the .realm file.

One thought it to give access to the parent folder containing the .realm file, which would then also allow the other files to be handled without interference from the OS.

I add this:

[[NSFileManager defaultManager] setAttributes:@{ NSFileProtectionKey: NSFileProtectionNone } ofItemAtPath:[containerURL absoluteString] error:&error];

But no change. The crash remains.

Frustrating for sure.

Can you verify the path returned with containerURLForSecurityApplicationGroupIdentifier exactly match one of the strings in the App Groups Entitlement?

Also, do you have multiple apps sharing the same Realm? If not, then that function is not the best choice.

Hi,
Not entirely sure what you mean, the url returns something like
"file:///Users/myuser/Library/Developer/CoreSimulator/Devices/AA079473-39F2-48EF-906F-39859FA1550B/data/Containers/Shared/AppGroup/BE41F274-4897-435D-A9A2-CD60C0C1DE50/

(on the simulator).

I use `containerURLForSecurityApplicationGroupIdentifier because I have a widget that references the database.

What I mean is from the Apple documentation for containerURLForSecurityApplicationGroupIdentifier

Parameters

groupIdentifier

A string that names the group whose shared directory you want to obtain. This input should exactly match one of the strings in the app’s App Groups Entitlement.

Got it.

Yes the same groupIdentifier is identical to the identifier groups entitlements as well as in the widget group entitlements.

Hmm. I created a new project and configured it very similar to yours and used the startup code you provided. I loaded some example data and a couple of classes (Person, Dog) and ran the app 100 times.

It worked every time.

That may indicate the issues is environmental - some setting in XCode or your project that’s possibly different than the default values which is what I used.

That code was not included but I assume you’re not using sync and Realm is a local Realm with no threading or other features like a migration block, and you’re viewDidLoad contains this

RLMRealm *defaultRealm = [RLMRealm defaultRealm];

Can you confirm?

Not using sync. It is a local realm. It does work most of the time.
Out of about around 1M of session in the last week, I have 62 crash reports from 38 users. So it doesn’t happen a lot, but when it does it happens more than once per user.
I can rule out it’s not related to free space on the device. And it’s not related to OS version.

Any other ideas on how to resolve this?

Would like to help but without some kind of reproducible example not sure what else to do as the presented code works.

Also, we have a number of apps that have very similar code and are not experiencing that crash - given we don’t have a large a dataset as you, if there were some kind of core issue, I would think there would be more similar reports.

Perhaps adding code to the app that generates log files and when a crash happens, give the user the ability to email you the log files.

OK,
So because according to the logs, in all cases identifierForVendor is nil, according to identifierForVendor | Apple Developer Documentation

"If the value is nil, wait and get the value again later. This happens, for example, after the device has been restarted but before the user has unlocked the device.

The value in this property remains the same while the app (or another app from the same vendor) is installed on the iOS device. The value changes when the user deletes all of that vendor’s apps from the device and subsequently reinstalls one or more of them. The value can also change when installing test builds using Xcode or when installing an app on a device using ad-hoc distribution. Therefore, if your app stores the value of this property anywhere, you should gracefully handle situations where the identifier changes"

This had to be related. I.E. in this case there’s no access to the folder no matter what. I have to work around it somehow.

Hi,

I’m updating that I have changed the code to use the default path, and I am still able to crash as seen here:

``Fatal error: ‘try!’ expression unexpectedly raised an error: Error Domain=io.realm Code=3 “Failed to open file at path ‘/var/mobile/Containers/Data/Application/EA977B3A-F1CC-4AD1-9247-27298B20385B/Documents/default.realm.lock’: Operation not permitted” UserInfo={Error Code=3, NSFilePath=/var/mobile/Containers/Data/Application/EA977B3A-F1CC-4AD1-9247-27298B20385B/Documents/default.realm.lock, Error Name=PermissionDenied, NSLocalizedDescription=Failed to open file at path ‘/var/mobile/Containers/Data/Application/EA977B3A-F1CC-4AD1-9247-27298B20385B/Documents/default.realm.lock’: Operation not permitted}`

This only occurs when identifierForVendor is nil. It’s likely the device is still locked, or has been reset.