Setup troubleshooting
The failures that show up on a first integration, and what each one actually means. For a failure that reached your catch block with a code attached, use the error code lookup instead.
getHealthPlatformStatus() never returns available
Health Connect is a separate app, not part of the OS on every device. The status tells you which situation you are in:
| Cause | What to do |
|---|---|
| The Health Connect app is missing or outdated | Call HealthConnector.launchHealthAppPageInAppStore() and let the user install or update it |
| The device runs below API 26 | Health Connect is unavailable; hide health features |
| A device policy or parental control blocks health data | Nothing to fix in code — explain the restriction to the user |
final status = await HealthConnector.getHealthPlatformStatus();
if (status != HealthPlatformStatus.available) {
await HealthConnector.launchHealthAppPageInAppStore();
return;
}Permission prompt never appears
Most likely: the type is not declared in your manifest. Health Connect refuses to prompt for a permission the app never declared, and the SDK reports this as ConfigurationException with permissionNotDeclared. Every type needs its own <uses-permission> entry:
<uses-permission android:name="android.permission.health.READ_STEPS" />
<uses-permission android:name="android.permission.health.WRITE_STEPS" />Second most likely: MainActivity still extends FlutterActivity. Permission requests use registerForActivityResult, which needs a FragmentActivity host. Switch to FlutterFragmentActivity — see step two of the Android setup.
Also check: the user may have already answered. Health Connect limits how often an app can re-prompt for the same permissions; send them to Health Connect's settings instead of prompting again.
Permission status is unknown on iOS
This is correct behavior, not a bug. HealthKit deliberately refuses to disclose read-authorization status so an app cannot infer what the user is hiding. Every iOS read permission reports unknown.
Design around it: run the query and treat an empty result as valid. Do not gate your UI on read status. If you genuinely need a signal, the probe workaround explains the tradeoff.
UnsupportedOperationException on a call that works on the other platform
The API you called exists on one platform only. The common cases:
| Call | Available on | Why |
|---|---|---|
updateRecord(), updateRecords() | Android only | HealthKit records are immutable |
getGrantedPermissions() | Android only | HealthKit will not let apps enumerate grants |
revokeAllPermissions() | Android only | iOS users revoke in Settings |
A data type marked @supportedOnAppleHealth… | iOS, sometimes iOS 16/17/18+ | No Health Connect equivalent |
Check the annotation reference, and branch on HealthConnector.healthPlatform when a feature is genuinely platform-specific. The iOS update workaround covers the most common of these.
Writes succeed but the data does not appear
- You are looking at the wrong app. Health Connect and Apple Health both scope views by source. Filter by your app.
- The time range excludes the record. Both stores index by the record's own timestamps, not by when you wrote it. A record backdated outside your query range will not appear in it.
- Android history limits. Health Connect only exposes the last 30 days by default. Reading older data requires
HealthPlatformFeature.readHealthDataHistory. iOS has no such limit.
Reads return fewer records than expected
- Pagination.
readRecords()returns one page. Followresponse.nextPageRequestuntil it isnull— see paginating. - The 30-day Android window again, if you are reading history.
- Another app owns the data and the user did not grant that type. Permissions are per data type, not per app.
Build fails after upgrading to v3.9.0+
Health Connector SDK v3.9.0 builds against Health Connect 1.2.0-alpha03, which requires SDK Extension 19 at compile time:
android {
compileSdkExtension 19
}If the build now passes but a write throws at runtime with UnsupportedOperationException, you have hit the separate SDK Extension 21 device check on ExerciseSessionSegmentEvent.weight. That one cannot be fixed in configuration — guard the write or omit the field. Details.
Still stuck
The Toolbox demo app runs every SDK operation against a real device. If a flow works there and not in your app, the difference is in configuration. If it fails there too, open an issue with your device, OS version, Flutter version, and the logs from a PrintLogProcessor.