Skip to content
AF
Troubleshooting

HealthKit errorInvalidArgument: Finding the Argument HealthKit Rejected

Last verified September 4, 2026 · 6 min read

Apple's documentation states one sentence for errorInvalidArgument — the app passed an invalid argument to the HealthKit API — and publishes no discussion paragraph. So Apple tells you an argument was rejected, and nothing about which one or why. In practice the constraint usually lives in the type rather than the call: an aggregation the type does not support, a unit from the wrong family, a predicate filtering on something the type does not have, or a reversed date range. Treat it as a programming error rather than an environmental one, log the arguments you passed, and reduce the call until the failure disappears.

Covered here:HealthKit

errorInvalidArgument is the bluntest case in the enum. Apple's documentation states one sentence — "The app passed an invalid argument to the HealthKit API." — and stops. There is no discussion paragraph, no list of offending arguments, and no hint about which of the several things you handed the framework it disliked. So this page does two separate jobs: it says exactly what Apple documents, and then, clearly separated from that, it walks the argument surfaces worth checking in practice.

What Apple documents#

The abstract quoted above is the entire published description of the case. Apple's platform list carries it back to the earliest HealthKit releases — iOS 8.0 and watchOS 2.0 — which fits a general-purpose validation failure rather than a feature-specific one. It is grouped with the other accessing errors in the HKError reference.

What Apple does not say is which argument, why, or whether the same call would succeed with different inputs. Any page that tells you "this error means your unit was wrong" is filling that gap with inference. The rest of this one is inference too, and labelled as such — a checklist of what to inspect, not a claim about what the framework decided.

Read the error like a compiler diagnostic you cannot see#

The mental model that works: something you passed did not satisfy a constraint that lives in the type, not in the call. HealthKit types carry their own rules about how they may be aggregated, what units they accept, and what may be attached to them, and a call that violates one of those rules is invalid regardless of how well-formed your code looks.

That reframes debugging. Instead of re-reading the call site, go and read the definition of the type you passed to it. The full set, with each identifier's own characteristics, is in the HealthKit identifier reference.

The argument surfaces worth checking, in order#

SurfaceWhat to verify
Type and aggregation optionThe option you asked for is one the type supports
UnitThe unit belongs to the type's unit family
PredicateIt filters on something the type actually has
Date rangeStart precedes end, and both are real dates
Statistics optionsCompatible with each other, not just with the type
Sample constructionValue, unit, and interval agree with the type's shape

1. Cumulative versus discrete#

This is the classic, and it is worth understanding rather than memorising. Some quantity types accumulate across an interval, so the sensible aggregation is a sum. Others are point measurements sampled repeatedly, so the sensible aggregation is an average, a minimum, or a maximum. Ask a running total from a type that is a series of independent readings, or an average from a counter, and you are asking for something the type has no definition for.

The split runs through the whole identifier catalogue, and getting it wrong is the single most common source of both invalid arguments and quietly nonsensical numbers. Sum or average works through which types fall on which side and why it matters for the figure you put on screen.

2. Units from the wrong family#

Each quantity type belongs to a unit family — a length, a mass, an energy, a count, a duration. Converting within the family is fine; presenting a value in a unit from another family is not a conversion at all. Check the unit family the identifier declares before you construct a quantity or format a result, especially in code paths that build units from user preferences or from a string.

3. Predicates that do not apply#

A predicate filtering on a property the type does not carry is an invalid argument even though it compiles. This bites most often in generic query layers where one builder serves every type: the code path that adds a workout-specific filter runs against a quantity type, and the framework rejects it.

4. Dates and intervals#

Verify start precedes end, that neither is a placeholder left over from an initialiser, and that an interval you supply for a bucketed query is positive. Day-boundary code that produces reversed or zero-width windows around daylight-saving changes is a real source of this — timezones and day boundaries covers why those calculations go wrong.

5. Anything constructed from configuration#

Types, units, and options assembled from a server response, a feature flag, or a saved preference are the arguments least likely to have been exercised by your tests. If the failure only happens for some users, look here first.

A diagnosis procedure#

  1. Log the full error, including the domain and code. Then log the arguments you passed — type identifier, unit, options, predicate description, and window — as a single structured line. Most invalid-argument bugs are solved by reading that line, not by stepping through the code.
  2. Reduce to the smallest call that still fails. Strip the predicate, then the options, then narrow to one type. The argument you remove that makes the error disappear is your answer.
  3. Rebuild from a known-good call. Take a query you know works for a type of the same shape and swap one thing at a time.
  4. Check the type's own documentation last. By this point you know which argument is implicated, so you are looking up one fact rather than reading everything.
  5. Add a test at the boundary. Every generic query builder should have coverage for each family of type it can be handed; testing a HealthKit integration is where that harness belongs.

Do not paper over it#

errorInvalidArgument is a programming error, not an environmental one, and it deserves the opposite handling from the runtime cases elsewhere in this cluster. A locked store is worth retrying and an unsupported device is worth degrading around, but a rejected argument will be rejected identically forever. Catching it and returning an empty result is how a permanent bug turns into a mysterious data gap that nobody can reproduce — and how it ends up misdiagnosed later as no data. Fail loudly in development, report it in production, and never silence it.

Because Apple publishes so little here, be careful about what you write in your own logs as well. "Invalid argument — probably the unit" is a guess that the next engineer will read as a finding. Record the arguments and let them draw the conclusion; the case for keeping raw codes and inferences apart is made in undocumented HealthKit errors.

Where to go next#

Apple's wording for every case sits in the HealthKit error reference, the type catalogue is at HealthKit identifiers, and the surrounding setup is in the HealthKit integration guide.

Frequently asked questions

What does Apple say causes errorInvalidArgument?
Only that the app passed an invalid argument to the HealthKit API. That abstract is the entire published description; there is no discussion paragraph naming which arguments qualify. Any source that tells you the case specifically means a unit problem or an options problem is inferring. Useful inference, but it should be labelled as inference rather than documentation.
Why do cumulative and discrete types cause invalid arguments?
Because the aggregation you ask for has to be one the type can define. A type that accumulates over an interval supports a running total; a type that is a series of independent readings supports averages, minimums, and maximums. Asking a counter for an average, or a set of point readings for a sum, is asking for something undefined.
Should I catch errorInvalidArgument and return an empty result?
No. Unlike a locked store or an unsupported device, a rejected argument will be rejected the same way forever, so catching it silently converts a permanent bug into a mysterious data gap nobody can reproduce. Fail loudly in development, report it in production, and log the arguments you passed alongside the code.

Keep reading

Elsewhere on the site

Pages that share this one’s concepts and sources, from other sections.

Next steps

Was this page useful?

Independent comparison, last reviewed September 4, 2026. Pricing, rate limits, and feature availability change often — confirm current details in each provider’s official documentation before you commit. Product and company names are trademarks of their respective owners; AIFitnessAPI is not affiliated with, endorsed by, or sponsored by any product listed here.

← All troubleshooting · by AIFitnessAPI