Context
Android Health Connect's aggregateGroupByDuration throws when a request would produce more than 5000 buckets:
android.health.connect.HealthConnectException: java.lang.IllegalArgumentException: Number of buckets must not exceed 5000
With a daily interval that caps each call at roughly 13.7 years. The limit isn't in the official docs — it only surfaces at runtime.
Current behavior
After v4.0.0-preview.6, GetAggregatedHealthDataByInterval surfaces this failure correctly via AggregatedIntervalReadResult.ErrorException instead of silently returning an empty list. But the call still fails entirely when the requested window exceeds 5000 buckets — consumers have to clamp their own range or accept the failure.
Proposal
Chunk the aggregation internally when the requested range × interval would exceed the platform limit:
- Compute the total bucket count from
timeRange and interval.
- If ≤ 5000 → single call (current path).
- If > 5000 → split the range into sub-windows of ≤ 5000 buckets, call
aggregateGroupByDuration once per sub-window, merge the resulting bucket lists in order.
Semantics stay identical from the consumer's perspective — a wide range just costs more IPC round trips.
Scope
- Android: implement chunking in
HealthService.GetAggregatedHealthDataByIntervalInternal (Platforms/Android). The 5000 constant should be named (e.g. HealthConnectMaxBucketsPerCall) and documented as an undocumented platform invariant, surfaced only via the runtime exception.
- iOS: investigate whether
HKStatisticsCollectionQuery has a similar ceiling for very wide ranges. If yes, apply the same chunking; if not, leave the iOS path untouched and note the asymmetry.
- Tests: unit tests for the chunking math (10000-bucket request → 2 sub-calls; exactly 5000 → 1 call; off-by-one boundary cases; non-daily intervals).
Acceptance
GetAggregatedHealthDataByInterval succeeds for arbitrarily wide ranges (subject to cancellation and memory), producing the same bucket set it would if the platform had no limit.
AggregatedIntervalReadResult.ErrorException no longer surfaces the 5000-bucket error for windows that differ only in size — only genuine platform errors (permission, SDK unavailable, cancellation, etc.) should propagate.
- Cancellation across chunks: a cancelled
CancellationToken mid-way through chunking aborts further sub-calls cleanly.
Related
- Follow-up to the error-visibility refactor shipped in v4.0.0-preview.6 that introduced
AggregatedIntervalReadResult — without this chunking work, consumers with wide sync windows still hit the failure; the refactor just made it visible instead of silent.
Context
Android Health Connect's
aggregateGroupByDurationthrows when a request would produce more than 5000 buckets:With a daily interval that caps each call at roughly 13.7 years. The limit isn't in the official docs — it only surfaces at runtime.
Current behavior
After v4.0.0-preview.6,
GetAggregatedHealthDataByIntervalsurfaces this failure correctly viaAggregatedIntervalReadResult.ErrorExceptioninstead of silently returning an empty list. But the call still fails entirely when the requested window exceeds 5000 buckets — consumers have to clamp their own range or accept the failure.Proposal
Chunk the aggregation internally when the requested range × interval would exceed the platform limit:
timeRangeandinterval.aggregateGroupByDurationonce per sub-window, merge the resulting bucket lists in order.Semantics stay identical from the consumer's perspective — a wide range just costs more IPC round trips.
Scope
HealthService.GetAggregatedHealthDataByIntervalInternal(Platforms/Android). The 5000 constant should be named (e.g.HealthConnectMaxBucketsPerCall) and documented as an undocumented platform invariant, surfaced only via the runtime exception.HKStatisticsCollectionQueryhas a similar ceiling for very wide ranges. If yes, apply the same chunking; if not, leave the iOS path untouched and note the asymmetry.Acceptance
GetAggregatedHealthDataByIntervalsucceeds for arbitrarily wide ranges (subject to cancellation and memory), producing the same bucket set it would if the platform had no limit.AggregatedIntervalReadResult.ErrorExceptionno longer surfaces the 5000-bucket error for windows that differ only in size — only genuine platform errors (permission, SDK unavailable, cancellation, etc.) should propagate.CancellationTokenmid-way through chunking aborts further sub-calls cleanly.Related
AggregatedIntervalReadResult— without this chunking work, consumers with wide sync windows still hit the failure; the refactor just made it visible instead of silent.