HKObserverQuery stops delivering updates in background on watchOS 26

Hello,

I’m building a health-related app for both watchOS and iOS, which needs to monitor certain health data (e.g., heart rate, active energy).

Before updating to watchOS 26, the queries worked reliably without any issues. However, after adapting to watchOS 26, some users have reported that health data updates stop being delivered.

What I’ve observed:

  • HKObserverQuery with enableBackgroundDelivery is set up normally.
  • On WatchOS 26, the query sometimes stops delivering updates entirely after a certain point, and once an update is missed, it may stop delivering further updates completely.
  • Restarting the Apple Watch temporarily restores delivery, but the problem reoccurs after some time.

This makes background health data monitoring unreliable for my app.

Here’s a simplified version of the code we are using:

guard let heartType = HKObjectType.quantityType(forIdentifier: .heartRate) else { return }

let query = HKObserverQuery(sampleType: heartType, predicate: nil) { query, completionHandler, error in
    if let error = error {
        logEvent("Observer error: \(error.localizedDescription)")
        return
    }
    logEvent("Heart rate changed")
    MyNotificationManager.shared.sendNotification() // Send a local notification
    
    completionHandler()
}

healthStore.execute(query)

healthStore.enableBackgroundDelivery(for: heartType, frequency: .hourly) { success, error in
    if success {
        logEvent("Background heart rate delivery enabled")
    } else {
        logEvent("Failed to enable background heart rate delivery: \(error?.localizedDescription ?? "Unknown error")")
    }
}

Could you please clarify:

  1. Is this a known issue with HKObserverQuery and enableBackgroundDelivery on watchOS 26?
  2. Are there any recommended workarounds or best practices to ensure continuous background delivery of health data?

Thank you in advance for your help.

Answered by DTS Engineer in 860644022

Yeah, this is a reported issue. I’d suggest that you file a feedback report and use the report to track the status of the issue.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

You must call the completion handler block in every case in your update handler.

In line 6, you handle the error without ever calling the completion handler block. Users who hit this error case will fail to tell the system that you are 'done'. This will eventually result in the system stop sending you background updates.

See the discuss here: https://developer.apple.com/documentation/healthkit/hkobserverquerycompletionhandler

Sorry, @HealthyPotter I missed part of the code earlier. In fact, the error scenario also has a callback.

        
        let query = HKObserverQuery(sampleType: heartType, predicate: nil) { query, completionHandler, error in
            if let error = error {
                logEvent("Observer 错误:\(error.localizedDescription)")
                completionHandler()
                return
            }
            logEvent("【心率有变化了")
            MyNotificationManager.shared.sendNotification() // 发了一个本地通知
            
            completionHandler()
        }
        
        healthStore.execute(query)
        
        healthStore.enableBackgroundDelivery(for: heartType, frequency: .hourly) { success, error in
            if success {
                logEvent("已启用后台心率监听")
            } else {
                logEvent("后台监听心率失败:\(error?.localizedDescription ?? "未知错误")")
            }
        }
        
】

Sorry, I missed part of the code. In fact, the error scenario also has a callback. I just sent a local notification and then immediately called completionHandler().

【guard let heartType = HKObjectType.quantityType(forIdentifier: .heartRate) else { return }
        
        let query = HKObserverQuery(sampleType: heartType, predicate: nil) { query, completionHandler, error in
            if let error = error {
                logEvent("Observer 错误:\(error.localizedDescription)")
                completionHandler()
                return
            }
            logEvent("【心率有变化了")
            MyNotificationManager.shared.sendNotification() // 发了一个本地通知
            
            completionHandler()
        }
        
        healthStore.execute(query)
        
        healthStore.enableBackgroundDelivery(for: heartType, frequency: .hourly) { success, error in
            if success {
                logEvent("已启用后台心率监听")
            } else {
                logEvent("后台监听心率失败:\(error?.localizedDescription ?? "未知错误")")
            }
        }
        
】
Accepted Answer

Yeah, this is a reported issue. I’d suggest that you file a feedback report and use the report to track the status of the issue.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

Hi Ziqiao, @DTS Engineer

I noticed that the feedback [FB20344425] status has been updated to “Investigation complete – Works as currently designed.”

Could you please confirm whether this means that the current behavior—where HKObserverQuery with enableBackgroundDelivery initially works but permanently stops pushing health data after one day—is expected under the current system design?

If this is indeed the intended behavior, are there any recommended approaches to ensure continuous or more reliable background data delivery for health-related apps on watchOS 26? Understanding the best practices for this scenario would be very helpful.

Thank you very much for your time and assistance!

Best regards, KeyCheung

Thanks for your following up. I see the following comment in your feedback report:

... needs to call completionHandler in every branch. Looking at the code snippet, if the observer query handler receives an error, completionHandler is never called.

If it is indeed that your observed query hit an error at some point and you failed to call the completionHandler, the system will stop giving you an update, which is an as-designed behavior.

Would you mind to check if that is your case?

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

Hi, Ziqiao Thanks for the clarification.

We’ve double-checked our implementation, and completionHandler() is indeed called in every branch, including when an error occurs. Here’s the exact code we’re using:

    if let error = error {
        logEvent("❌ Observer 错误:\(error.localizedDescription)")
        completionHandler()
        return
    }
    logEvent("【💓】有变化了,准备Check")
    
    self.dataCheck(source: "heartRate") {
        logEvent("Check 结束,回调")
        completionHandler()
    }
}
self.healthStore.execute(query)

// 启用后台 delivery
self.healthStore.enableBackgroundDelivery(for: heartType, frequency: .immediate) { success, error in
    logEvent(success ? "✅ 已启用后台监听_\(heartType)" : "❌ 启用_\(heartType)失败:\(error?.localizedDescription ?? "未知")")
}

Even though completionHandler() is always invoked, background delivery still stops after some time (usually within 2–3 days). Restarting the watch temporarily restores updates, but they eventually stop again.

We’ve tested this on:

Xcode 16.0 (26.0.1 / 17A400)

Devices & watch OS

  1. Apple Watch Series 8 / watchOS 26.1(23S5002i)
  2. Apple Watch Series 10 / watchOS 26.1(23S5017d)

If possible, could you help confirm whether our current implementation aligns with the recommended usage for HKObserverQuery background delivery?

Best KeyCheung

The code snippet provided above looks good. However, the one in your feedback report, as shown below, doesn't call completionHandler when an error happens, which led to the comment from the HealthKit folks.

let query = HKObserverQuery(sampleType: heartType, predicate: nil) { query, completionHandler, error in
	if let error = error {
		logEvent("Observer error: \(error.localizedDescription)")
		return
	}
	...
}

In this situation, you can follow up with your feedback report by updating the code snippet, or even file a new feedback report, to be very clear that you call completionHandler in all your code paths but the issue is still there.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

HKObserverQuery stops delivering updates in background on watchOS 26
 
 
Q