react-native-health icon indicating copy to clipboard operation
react-native-health copied to clipboard

Fatal Exception: NSInvalidArgumentException when retrieving health data

Open rnbrk opened this issue 3 years ago • 16 comments

Thanks for creating this library.

Describe the bug After migrating an app from rn-apple-healthkit to react-native-health there have been a large number of crashes reported in Crashlytics. The crash seems to occur when health data is received. However I have been unable to reproduce this error myself on an iPhone simulator or a physical device.

This is the error: Fatal Exception: NSInvalidArgumentException ***[__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object from objects[1]

Which seems to happen inside the completionHandler in the method fetchSumOfSamplesOnDayForType. This method is called from many other methods that retrieve various types of health data such as getStepCountOnDay.

Where one of these values in *response is nil, which due to the if-statement should be startDate or endDate. And buildISO8601StringFromDate can return nil if there is an error.

Inside the completionHandler:

if (!value && value != 0) {
            callback(@[RCTJSErrorFromNSError(error)]);
            return;
        }

         NSDictionary *response = @{
                 @"value" : @(value),
                 @"startDate" : [RCTAppleHealthKit buildISO8601StringFromDate:startDate],
                 @"endDate" : [RCTAppleHealthKit buildISO8601StringFromDate:endDate],
         };

        callback(@[[NSNull null], response]);

Do you have an idea what might cause this error?

These are the permissions that I use:

const appleHealthKitOptions = {
    permissions: {
        read: [
            AppleHealthKit.Constants.Permissions.StepCount,
            AppleHealthKit.Constants.Permissions.SleepAnalysis,
            AppleHealthKit.Constants.Permissions.HeartRate,
            AppleHealthKit.Constants.Permissions.DistanceCycling
        ],
        write: []
    }
};

And these AppleHealthKit methods:

AppleHealthKit.getDailyStepCountSamples
AppleHealthKit.getDailyDistanceCyclingSamples
AppleHealthKit.getSleepSamples
AppleHealthKit.getHeartRateSamples

To Reproduce Unfortunately I cannot reproduce it myself.

Smartphone (please complete the following information):

  • Device: It happens on many different types of iPhones
  • OS: Both iOS 13 and 14
  • Version 1.7.0

Thanks a lot.

rnbrk avatar Jun 16 '21 14:06 rnbrk

Hey @rnbrk, really weird, I could not reproduce this as well, please share more information if you have

macelai avatar Jun 30 '21 12:06 macelai

Also running into this. Seems to only be when fetching StepCount

*** -[__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object from objects[1] Screen Shot 2021-07-15 at 5 47 19 PM

likeaj6 avatar Jul 16 '21 00:07 likeaj6

@macelai @lucaspbordignon We are also having the same exact issue and not able to reproduce it. But this can potentially be fixed by just having default values for the cases when start or end date are null in the buildISO8601StringFromDate assignment right? Since this is in the method fetchSumOfSamplesOnDayForType, maybe using the "day" as the start and end date? Wdyt?

j-carvalho avatar Aug 31 '21 13:08 j-carvalho

We are facing the same issue, any news on this? We are also using Version 1.7 so is there a chance that this is fixed in the latest release?

c-goettert avatar Dec 10 '21 12:12 c-goettert

@lucaspbordignon I am using 1.12 version of this library and my users get the same crashes every day. I don't understand the reason. I can't reproduce this bug but see them on bugsnag. Any solution, advice? Maybe these bugs are related to iOS 15 (and later) updates? @c-goettert @rnbrk Did you find any working solution to prevent this bug?

gigby avatar Jan 31 '22 17:01 gigby

@gigby unfortunatley no, we couldn't find a solution / reason for this bug yet..

c-goettert avatar Feb 07 '22 16:02 c-goettert

@c-goettert I found out. It happens on iOS 15.2 or later due to prewarming feature. You can easily awoid these bugs if you don't call Healthkit from a background app state. No background calls no these bugs

gigby avatar Feb 07 '22 17:02 gigby

@gigby thanks for letting me know, we indeed use background calls to fetch health data. We'll deactivate those and see if this will solve the issue.

c-goettert avatar Feb 16 '22 09:02 c-goettert

@gigby unfortunatly we still see this issue after disabling our background task. How did you make sure that Healthkit is not called from a background state? Did you use AppState-Events from React Native or did you just remove any existing Background Observers? Or did you remove Background-Fetch Entitlement from your app completely?

c-goettert avatar Apr 25 '22 10:04 c-goettert

@c-goettert I used AppState events from RN. Very simple. And now I don't see these errors in Bugsnag although earlier I observed hundreds of them per 1 week an example

export async function initHealthkit(perms: Array<string> = []) {
  const healthKitOptions = {
    permissions: {
      read: (perms && perms.length) ? perms : ALL_REQUIRED_IOS_HEALTH_PERMISSIONS,
    },
  } as HealthKitPermissions;

  let result = false;
  // calls to apple healthkit on the background state may cause crashes on ios 15 and later
  const isBackground = AppStateListener.isAppInBackground();

  if (!isBackground) {
    result = await new Promise<boolean>((res) => {
      AppleHealthKit.initHealthKit(healthKitOptions, (err, results) => {
        if (err) {
          // OMG! error here is string!
          eNotifier(new Error(err));

          res(false);
        }

        res(!!results);
      });
    });
  }

  return result;
}

gigby avatar Apr 25 '22 20:04 gigby

@c-goettert And somewhere in code I use previous func to get some data like this:

export async function getSleepHours(timeFrom?: number | Date, timeTo: number | Date = Date.now()) {
  const result: Array<TSleepEventRawIos> = [];

  const isGranted = await initHealthkit([AppleHealthKit.Constants.Permissions.SleepAnalysis]);

  if (isGranted) {
    let timeStart;
   // code here
  }

gigby avatar Apr 25 '22 21:04 gigby

@c-goettert Were you able to look into the thing mentioned above by @gigby?

I'm getting this same issue but not on every phone that runs this code. I'm not sure if it's something related to initializing apple health after checking if the app isn't in the background as our code runs when the app is open.

hammad0316 avatar May 24 '22 20:05 hammad0316

Any update on this bug? We are receiving this error mostly on iOS 15, and few in iOS 14. We do not intentionally call any method from background state.

egealpay avatar Jun 29 '22 12:06 egealpay

Having the same issue

pavelbabenko avatar Jul 14 '22 14:07 pavelbabenko

+1 Looks like mostly users on iOS 15

brandon-austin-lark avatar Aug 15 '22 18:08 brandon-austin-lark

We are also still facing this issue. For the next release I will try @gigby's solution to check if the app is in foreground before interacting with HealthKit.

c-goettert avatar Sep 05 '22 08:09 c-goettert

We're getting the same error/crash when calling AppleHealthKit.getStepCount. Did anyone manage to find a fix/workaround?

UPDATE

startDate and endDate are nil. These values shouldn't be passed along as arguments on the callback. https://github.com/agencyenterprise/react-native-health/blob/38603c64134fbf32cef6d4df453e2cc06849bf07/RCTAppleHealthKit/RCTAppleHealthKit%2BMethods_Fitness.m#L37

yhanssens avatar Oct 18 '22 08:10 yhanssens

I'm having this issue, did anybody figure it out?

lhestermonroyo avatar Dec 07 '22 08:12 lhestermonroyo

Hey guys, I plan to take a deep look into this crash in a few days. If you have any additional information it would be very welcome, thanks

GGGava avatar Jan 17 '23 17:01 GGGava

Thank you for looking into this, we are still regularly getting lots of these in our error reporting. For us I can say that it only seems to occur when the app runs in background mode. It might be somehow related to the iOS rights system, e.g. that values may not be accessed while the phone is locked or similar. This would fit the error messages we get from the lib before the exception:

Error while trying to get blood pressure samples from healthkit: , error getting blood pressure samples:Error Domain=com.apple.healthkit Code=6 "Protected health data is inaccessible" UserInfo={NSLocalizedDescription=Protected health data is inaccessible}

This is what an example stack-trace looks like (probably not very helpful):

libobjc.A.dylib                     0x000000019a6c4f54 objc_exception_throw + 60
CoreFoundation                      0x0000000182159530 B2D21CFD-378C-36D5-BAF7-3F70599CFEFC + 1713456
CoreFoundation                      0x00000001821646ac B2D21CFD-378C-36D5-BAF7-3F70599CFEFC + 1758892
CoreFoundation                      0x000000018200d464 B2D21CFD-378C-36D5-BAF7-3F70599CFEFC + 353380
CoreFoundation                      0x000000018202be0c B2D21CFD-378C-36D5-BAF7-3F70599CFEFC + 478732
App                                 0x00000001022e4744 _ZN5folly6detail15str_to_integralIxEENS_8ExpectedIT_NS_14ConversionCodeEEEPNS_5RangeIPKcEE + 161376
App                                 0x00000001022f1eb8 _ZN5folly6detail15str_to_integralIxEENS_8ExpectedIT_NS_14ConversionCodeEEEPNS_5RangeIPKcEE + 216532
libdispatch.dylib                   0x0000000181cc0914 A5CBAAB3-E389-3548-BAAC-FAB18411B94A + 10516
libdispatch.dylib                   0x0000000181cc2660 A5CBAAB3-E389-3548-BAAC-FAB18411B94A + 18016
libdispatch.dylib                   0x0000000181cc9de4 A5CBAAB3-E389-3548-BAAC-FAB18411B94A + 48612
libdispatch.dylib                   0x0000000181cca98c A5CBAAB3-E389-3548-BAAC-FAB18411B94A + 51596
libdispatch.dylib                   0x0000000181cd51a8 A5CBAAB3-E389-3548-BAAC-FAB18411B94A + 94632
libsystem_pthread.dylib             0x00000001f23620f4 _pthread_wqthread + 288
libsystem_pthread.dylib             0x00000001f2361e94 start_wqthread + 8```

c-goettert avatar Jan 19 '23 09:01 c-goettert

Seems related to #97. Got this same message Fatal Exception: NSInvalidArgumentException ***[__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object from objects[1] while testing #97.

Both issues are related to HealthKit denying access to data. I'm still investigating and keep you guys posted.

GGGava avatar Jan 19 '23 12:01 GGGava

Fixed by #280

GGGava avatar Jan 19 '23 21:01 GGGava

I fixed #97 and I believe it will fix this issue too. Please update to v1.13.6 and let me know if the issue persists.

GGGava avatar Jan 19 '23 21:01 GGGava