---
title: "HealthKit errorDatabaseInaccessible: Reads Fail While the Device Is Locked"
canonical: "https://aifitnessapi.com/fix/healthkit-database-inaccessible"
cluster: "Troubleshooting"
primary_query: "healthkit errordatabaseinaccessible"
last_reviewed: "2026-09-04"
description: "Apple states reads fail while the device is locked but saves still work. Why this is a background-only failure, and how to retry it without losing data."
publisher: "AIFitnessAPI — independent, not sponsored"
cite_as: "\"HealthKit errorDatabaseInaccessible: Reads Fail While the Device Is Locked\", AIFitnessAPI, https://aifitnessapi.com/fix/healthkit-database-inaccessible"
---

# HealthKit errorDatabaseInaccessible: Reads Fail While the Device Is Locked

> HealthKit returns errorDatabaseInaccessible when your app queries the store while the device is locked. Apple's documentation states that reads fail in this state but saves still work: the data goes into a temporary file that is merged when the user unlocks the device. That makes this a background problem, because a foregrounded app is running on an unlocked device. Treat it as transient rather than terminal, resume the read after the device is unlocked, and never record the failed read as a gap in the user's history.

- Canonical: https://aifitnessapi.com/fix/healthkit-database-inaccessible
- Last reviewed: 2026-09-04
- Publisher: AIFitnessAPI (https://aifitnessapi.com) — independent, not sponsored
- Cite as: "HealthKit errorDatabaseInaccessible: Reads Fail While the Device Is Locked", AIFitnessAPI, https://aifitnessapi.com/fix/healthkit-database-inaccessible

---

Your app wakes in the background, runs a HealthKit query, and the completion handler hands back `errorDatabaseInaccessible`. The same query works every single time you test it with the phone unlocked in your hand. Your predicate is fine, your authorization is fine, your entitlements are fine. The store was protected at the moment you asked, and that is the entire bug.

## What Apple documents

Apple's documentation states the abstract for this case as: "The HealthKit data is unavailable because it's protected and the device is locked." The discussion is unusually specific for a case in this enum, and it is worth reading whole:

> This error occurs when your app queries for HealthKit data while the device is locked. You can, however, still save data. This data is saved into a temporary file, which is merged with HealthKit's data when the user unlocks their device.

Two facts fall out of that paragraph, and every design decision below rests on them. Queries fail while the device is locked. Saves do not — Apple states the data goes into a temporary file and is merged once the user unlocks. Everything else on this page is engineering practice, and is labelled as such rather than dressed up as documented behaviour. The case is listed on every platform in Apple's [HKError reference](/healthkit-errors), including watchOS.

## The asymmetry is the whole design constraint

| While the device is locked | What Apple's discussion states |
| --- | --- |
| Query for existing samples | Fails — this is the error you are holding |
| Save new samples | Still permitted |
| Where a save goes | Into a temporary file |
| When it reaches HealthKit | When the user unlocks the device |

Most sync code is written as read-then-reconcile-then-write, and that shape breaks in exactly one place under lock: the read. If your background job pulls the last day of samples, diffs them, and writes a derived summary back, the pull fails and the whole job aborts — even though the write half would have gone through. A job that can emit its writes independently of its reads keeps working on a locked phone. A job that cannot, stalls until the user picks up the device.

## Why this only ever shows up in the background

In the foreground the error is nearly unreachable: if your UI is on screen, the device is unlocked. The paths that run with the screen off are the ones that meet a protected store — background delivery wake-ups, background refresh work, and anything you deliberately schedule overnight. Teams often move heavy syncing to quiet hours to spare the battery and the network, which is precisely when the phone is locked for the longest stretch. That is an optimisation straight into the failure mode.

So treat this error as a property of *when* your code runs, not of what it asks for. The surrounding mechanics — registering for wake-ups, finishing the work before the system suspends you — are covered in [background sync](/architecture/background-sync); if your wake path never fires at all, that is a different fault, and it starts at [HealthKit background delivery not working](/fix/healthkit-background-delivery-not-working).

## Diagnosis order

1. **Read the actual code, not the symptom.** Log the error domain and code and confirm you have `errorDatabaseInaccessible` rather than an empty result. An empty result is not an error and means something else entirely — see [HealthKit errorNoData](/fix/healthkit-error-no-data).
2. **Reproduce on purpose.** Lock the device, trigger the wake path, and watch the failure appear. If you cannot reproduce it that way, the lock state is probably not your cause.
3. **Check whether your saves fail too.** Per Apple's discussion, saving should still work while locked. If writes are failing as well, stop chasing lock state and start with the authorization state machine: [errorAuthorizationNotDetermined](/fix/healthkit-authorization-not-determined) covers the never-asked case.
4. **Check what your job did with the failure.** Many teams discover the error was being caught, counted as "zero new samples", and written into a summary table as a gap. That is a data-quality bug wearing an error's clothes.

## Retry design, as practice

None of the following is Apple's documented behaviour; it is how we would build around what Apple documents.

- **Classify it as transient, in its own bucket.** Terminal conditions such as an unsupported device or an [MDM restriction](/fix/healthkit-data-restricted-mdm) will never succeed on retry. This one will succeed the moment the user unlocks. Same failure shape, opposite handling.
- **Do not spin.** A tight retry loop inside a background wake-up burns your execution window against a device that may stay locked for hours, and buys nothing.
- **Resume on unlock, not on a timer.** The condition you are waiting for is a user action. Re-run the work when the app next becomes active, or on the next wake-up after the device has been unlocked, rather than scheduling blind retries through the night.
- **Keep a durable cursor.** If the read never happened, the cursor must not move. Checkpointing so an interrupted run resumes cleanly is the pattern in [incremental sync](/architecture/incremental-sync).
- **Never record it as absence.** A locked store means "we could not look", which is not the same as "there was nothing there". Anything that feeds charts, streaks, or coaching logic should carry that distinction — [missing data and gaps](/architecture/missing-data-and-gaps) is the wider version of this argument.
- **Say nothing to the user.** There is no in-app remedy to offer, and no dialog that helps. Fail quietly, retry later, and let the next successful sync fill in.

## On the watch

Apple lists this case for watchOS along with the other platforms, so a workout or complication refresh that reads history can hit it too. Wrist-off and locked states on a watch are ordinary, not exceptional, so the same rule applies: buffer, resume, and never treat the failure as a gap. The execution model that decides when your watch code runs at all is set out in [Apple Watch background execution](/watch-apps/apple-watch-background-execution).

## Symptom to action

| What you observe | What it means | What to do |
| --- | --- | --- |
| Background read fails, foreground read works | The store was protected while locked | Retry after unlock; keep the cursor |
| Reads and writes both fail | Not a lock problem | Check authorization and setup |
| Query returns empty with no error | Not this error at all | Read [errorNoData](/fix/healthkit-error-no-data) |
| Failure repeats forever on the same device | Terminal, not transient | Check unavailable or restricted cases |

## Where to go next

If you are still deciding which HealthKit failures deserve a retry policy at all, the full enum with Apple's own wording is at [the HKError reference](/healthkit-errors), and the honest limits of that reference — cases Apple ships with no description whatsoever — are covered in [undocumented HealthKit errors](/fix/healthkit-undocumented-errors). For the end-to-end setup this error assumes you already have, see the [HealthKit integration guide](/integrate/healthkit).

## FAQ

### Why does my background HealthKit read fail when the same query works in the app?

Because the device was locked when the background job ran. Apple's documentation states this error occurs when your app queries HealthKit data while the device is locked. In the foreground the device is unlocked by definition, so the identical query succeeds. The difference is timing and lock state, not your predicate, entitlements, or authorization setup.

[Permalink](https://aifitnessapi.com/fix/healthkit-database-inaccessible#faq-1)

### Can my app still save HealthKit data while the device is locked?

Apple's discussion states that you can still save data while the device is locked. It says the data is written into a temporary file, which is merged with HealthKit's data when the user unlocks their device. So a job that only reads will fail, while a job that only writes keeps working, which is a useful thing to design around.

[Permalink](https://aifitnessapi.com/fix/healthkit-database-inaccessible#faq-2)

### Should I retry immediately after errorDatabaseInaccessible?

As a practice, no. A tight retry loop burns your background execution window against a device that may stay locked for hours. Classify the failure as transient, leave your sync cursor where it was, and re-run the work when the app next becomes active or on a wake-up after the device has been unlocked.

[Permalink](https://aifitnessapi.com/fix/healthkit-database-inaccessible#faq-3)
