Thanks for being a part of WWDC25!

How did we do? We’d love to know your thoughts on this year’s conference. Take the survey here

WatchOS HealthKit HKObserverQuery crashes in background

I have a watchOS app with a connected iOS app using Swift and SwiftUI. The watchOS app should read heart rate date in the background using HKOberserQuery and enableBackgroundDelivery(), send the data to the iPhone app via WCSession. The iPhone app then sends the data to a Firebase project. The issue I am facing now it that the app with the HKObserverQuery works fine when the app is in the foreground, but when the app runs in the background, the observer query gets triggered for the first time (after one hour), but then always get terminated from the watchdog timeout with the following error message: CSLHandleBackgroundHealthKitQueryAction scene-create watchdog transgression: app<app.nanacare.nanacare.nanaCareHealthSync.watchkitapp((null))>:14451 exhausted real (wall clock) time allowance of 15.00 seconds

I am using Xcode 16.3 on MacOS 15.4 The App is running on iOS 18.4 and watchOS 11.4

What is the reason for this this issue? I only do a simple SampleQuery to fetch the latest heart rate data inside the HKObserverQuery and then call the completionHandler. The query itself takes less than one second.

Or is there a better approach to read continuously heart rate data from healthKit in the background on watchOS? I don't have an active workout session, and I don't need all heart rate data. Once every 15 minutes or so would be enough.

In the use case you described, HKOberserQuery + enableBackgroundDelivery is the right way to go.

When you use enableBackgroundDelivery in watchOS though, the background updates share a budget with WKApplicationRefreshBackgroundTask tasks. Your app can receive four updates (or background app refresh tasks) an hour, as long as it has a complication on the active watch face. This is documented here.

When your app is woken up to run the update handler of the observer query, watchOS assigns a period of time for your app to run in the background. The error message you provided indicates that your app ran out of the time allowance.

In the case where you "do a simple SampleQuery to fetch the latest heart rate data inside the HKObserverQuery," 15 seconds is quite enough, and so I am wondering if you have any code path that failed to call the completionHandler passed to the updateHandler of your observer query, which had watchOS believe that your observer query was running in the background for ever. You can double check if that is the case.

The other factor is Watch Connectivity. Your watchOS app uses WCSession to send data to your companion iOS app when running in the background. The execution time is counted against the budget as well. For debugging purpose, you can temporarily disable the data transfer, and check if the crash still happens.

If you've reviewed all your code paths, and are confident that your code should not hit the budget, I’d suggest that you file a feedback report with the following information for the watchOS folks to investigate:

  • The relevant code snippets, or even better, a minimal sample that reproduces the issue.
  • A full crash report.
  • A co-sysdiagnose. See the Instructions here for how to capture one.

If you do so, please share your report ID here for folks to track.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

Hi Ziqiao, thanks for the reply. I have already tried disabling the data transfer to the iPhone via wcsession, but the same error still occurs. Is there any sample code / project from apple about how to implement this? One other question came to my mind: You said that my app can receive 4 updates per hour as long as it has a complication on the active watch face. I don't have a complication for the app. Does this mean that the app can only receive up to 1 update per hour from the HKObserverQuery? What would happen if I also want to get updates from other data types, not just heart rate. For example in addition also step count, calories, blood oxygen. If I would register an HKObserverQuery for each of these 4 data types with a frequency of hourly. If all 4 HKObserverQueries "wake up" every hour, would that already be 4 background updates per hour? Which would be too much already without a complication. Thanks & best regards, Tobias

I have the same problem, I am monitoring HRV data using HKOberserQuery + enableBackgroundDelivery with HKUpdateFrequency.hourly . in HKOberserQuery i only gets the latest one HRV sample.

I make sure HKObserverQueryCompletionHandler is called correctly, but I see a lot of CSLHandleBackgroundHealthKitQueryAction crash log on the watch logs, and I'm seeing the same logs on other apps too!

@tobiasbader:

Does this mean that the app can only receive up to 1 update per hour from the HKObserverQuery? What would happen if I also want to get updates from other data types, not just heart rate.

When you use HKOberserQuery with background delivery enabled to monitor some data points, assuming that your app is suspended and the first change happens, the system will wake up your app and allow it to run for a short period of time. If a second change comes within the time allowance, your app isn't in the suspended state, and so no waking-up is needed; otherwise, your app will be suspended again shortly after you call the completion handler (HKObserverQueryCompletionHandler) to signal that you've handled the first change. If the completion handler is not called, the system will crash your app after the time allowance, which is what your error message indicates.

@blacksun

I make sure HKObserverQueryCompletionHandler is called correctly, but I see a lot of CSLHandleBackgroundHealthKitQueryAction crash log on the watch logs, and I'm seeing the same logs on other apps too!

In this case, I'd suggest that you start with filing a feedback report, as mentioned in my previous post.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

Hello Ziqiao, thanks for the information. But you didn't answer my questions from the previous comment. Therefore could you please answer these questions?

  1. Is there any sample code / project from apple about how to implement background HealthKit queries on WatchOS?
  2. How many updates per hour can a WatchOS app receive in the background if there is no complication on the active watch face?
  3. If I have observer queries registered for 4 different data types, each trigger of these observer queries would count as one separate wake up if they don't occur at the same time or directly after each other within the time allowance of the first one, correct?
  4. Is it better / recommended to read HealthKit data in the background on iOS instead of WatchOS? On iOS I discovered the problem that I cannot read heart rate data in the background if the iPhone is locked.
  5. Is there a way to read heart rate data in the background on iOS if the iPhone is locked?
  6. Is there a list of data types from HealthKit which ones can be read in the background if the iPhone is locked and which ones cannot?

Thanks a lot! Tobias

Hello Ziqiao, would you please reply to Tobias' points. Thank you in advance! Manuel

WatchOS HealthKit HKObserverQuery crashes in background
 
 
Q