Google Health API errors: the v4 error catalog and troubleshooting
Read from Google’s documentation on 2026-10-17 · discovery document revision 20261014 · Google’s error catalog last updated 2026-10-01
Google’s v4 error catalog lists 63 reasons across HTTP 400, 401, 403, 404, 409, 429 and 500, and adds: “This list contains some error messages related to its API, but is not a complete list of those messages.” The one a Fitbit Web API migration meets first is ACCOUNT_NOT_LINKED: HTTP 400 with status FAILED_PRECONDITION, when a user consents before their Google Account is linked to Google Health. Google says to call users.getIdentity right after the OAuth exchange and send the user to the Google Health app to link.
ACCOUNT_NOT_LINKED
Handle unlinked Google Accounts
A user must sign in to the Google Health mobile app to link Google Health to their Google Account before your app can sync data through the Google Health API. See Link Google Health before OAuth consent. Because Google OAuth 2.0 authenticates any valid Google Account during consent, it cannot block accounts that don't yet have an active Google Health profile.
If a user completes Google OAuth consent before creating a Google Health profile or before migrating their legacy Fitbit account to their Google Account, calling users.getIdentity or a data endpoint returns an HTTP 400 Bad Request error with status FAILED_PRECONDITION and reason ACCOUNT_NOT_LINKED:
{
"error": {
"code": 400,
"message": "The account is not linked to Google Health.",
"status": "FAILED_PRECONDITION",
"details": [
{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "ACCOUNT_NOT_LINKED",
"domain": "health.googleapis.com",
"metadata": {
"redirect_uri": "https://fitbit.google.com/auth/signup"
}
}
]
}
}To verify account access and handle this error:
- Exchange the OAuth authorization code for tokens and immediately call
users.getIdentity(GET https://health.googleapis.com/v4/users/me/identity) before marking the account as linked in your app UI. - If
users.getIdentityor a background data sync call returns HTTP400with reasonACCOUNT_NOT_LINKED, don't mark the account as connected. If the user is migrating from the legacy Fitbit Web API, keep their existing Fitbit connection active and don't revoke their legacy Fitbit tokens. - Display an actionable prompt that addresses both new users who have never created a Google Health or Fitbit account and existing Fitbit users who have not yet migrated to a Google Account:
"Your Google Account isn't linked to Google Health yet. Open the Google Health mobile app and sign in with your Google Account to create a profile, or move your existing Fitbit account to your Google Account, then return here to connect." - Provide a call-to-action button that opens the
redirect_urifrom the error metadata (https://fitbit.google.com/auth/signup) or direct legacy Fitbit users to the Fitbit account migration help article.
Quoted from Google's troubleshooting guide, last updated 2026-09-28, read 2026-10-17.
The catalog describes ACCOUNT_NOT_LINKED as “The Google account is not linked to a Fitbit account.”; the example response above carries the message “The account is not linked to Google Health.”. Both are Google’s text. Our suggestion: match on the reason, not the message.
The v4 error catalog
The following table lists HTTP status codes and associated errors that you might encounter when interacting with our API. Each status code corresponds to one or more reasons and descriptions to help you troubleshoot and handle errors effectively in your application. Within the descriptions, variables denoted by curly braces ({}) represent placeholders for values that are specific to your request.
HTTP 400 (52)
| Reason | Google’s description |
|---|---|
ACCOUNT_NOT_LINKED | The Google account is not linked to a Fitbit account. |
INVALID_PARENT_DATA_TYPE_COLLECTION_FORMAT | Invalid {field} format. Expected: {expectedFormat}; Got: {actualValue}. |
INVALID_PARENT_DATA_TYPE_COLLECTION | Invalid data type ID referenced in the parent data type collection: {dataType}. |
INVALID_FILTER_FORMAT | Invalid filter format. |
INVALID_DATA_POINT_DATA_SOURCE_FAMILY | Invalid data source family in filter. |
INVALID_DATA_POINT_FILTER | Invalid filter. |
INVALID_DATA_POINT_FILTER_SYNTAX | Invalid filter syntax. |
INVALID_DATA_POINT_FILTER_MISSING_TOKEN | Invalid filter: missing token. |
INVALID_DATA_POINT_FILTER_UNEXPECTED_TOKEN | Invalid filter: unexpected token. |
INVALID_DATA_POINT_FILTER_UNEXPECTED_END_OF_INPUT | Invalid filter: unexpected end of input. |
INVALID_DATA_POINT_FILTER_EXPRESSION_STRUCTURE | Invalid filter expression structure. |
INVALID_DATA_POINT_FILTER_RESTRICTION_COMPARABLE | Invalid filter restriction comparable. |
INVALID_DATA_POINT_FILTER_DATA_TYPE_RESTRICTION | Invalid filter data type restriction. |
INVALID_TIME_RANGE_INTERVAL_FORMAT | Civil time provided for a non-daily rollup request or physical time provided for a daily rollup request. |
INVALID_TIME_RANGE | Query end time must be strictly larger than start time. |
INVALID_ROLLUP_QUERY_DURATION | The duration covered by window_size_days * page_size must not exceed {maxDurationDays} days for {dataType}. |
INVALID_ROLLUP_WINDOW | Rollup window size must be at least 1 second. |
INVALID_DATA_POINT_FILTER_MIXED_DATA_TYPE_RESTRICTIONS | Filter cannot contain restrictions for multiple data types. |
INVALID_DATA_POINT_FILTER_MIXED_TIME_RESTRICTIONS | Filter cannot contain both physical and civil time ranges. |
INVALID_DATA_POINT_FILTER_DATA_TYPE_MEMBER | Invalid filter member for data type. |
INVALID_DATA_POINT_FILTER_RESTRICTION_COMPARATOR | Invalid filter restriction comparator. |
INVALID_DATA_POINT_FILTER_TIMESTAMP_FORMAT | Invalid filter timestamp format. |
INVALID_DATA_POINT_FILTER_CIVIL_DATE_TIME_FORMAT | Invalid filter civil date time format. |
INVALID_CIVIL_DATE_TIME | Invalid civil date time: {reason}. |
INVALID_DATA_POINT_FILTER_RESTRICTION_ARGUMENT | Invalid filter restriction argument. |
INVALID_DATA_POINT_FILTER_COLLECTION_MISMATCH | Data type in filter does not match parent data type collection. |
INVALID_DATA_POINT_NAME | Invalid data point name. |
DATA_POINT_NOT_OWNED_BY_CLIENT | Data point is not owned by the client. |
MISSING_DATA_POINT_NAMES | Missing data point names. |
MISSING_DATA_POINT_FILTER | Filter must be set for purge request. |
DATA_TYPE_MISMATCH | The data point in the update request must have the same data type as the parent. |
UPDATE_ONLY_UPSERT_SUPPORTED | Update only supports upsert. Please set allow_missing to true. |
MISSING_DATA_POINT_ID | Missing data point ID for update. |
MISSING_DATA_POINT_VALUE | Missing data point value. |
INVALID_PROFILE_DATA | Invalid value provided for field {field}. Provided value: {providedValue}. Accepted values: {acceptedValues}. |
INVALID_FIELD_MASK_DATA | Request contains invalid field mask data. |
INVALID_PAGE_SIZE | Page size cannot be negative, but was {actualValue}. |
INVALID_PAGE_TOKEN | Invalid page token. |
MULTIPLE_DATA_TYPES_UNSUPPORTED | Multiple data types are not supported. |
UNSUPPORTED_DATA_TYPE_ACTION | The action is not supported for the data type. |
INVALID_DATA_TYPE | Invalid data type provided: {dataType}. |
MISSING_SUBSCRIBER | Subscriber must be provided. |
INVALID_SUBSCRIBER_NAME | Invalid subscriber name: {subscriberName}. |
MISSING_SUBSCRIPTION | Subscription must be provided. |
INVALID_SUBSCRIPTION_NAME | Invalid subscription name: {subscriptionName}. |
MISSING_DATA_TYPES | Data types must be specified. |
DATA_TYPES_CANNOT_BE_EMPTY | Data types cannot be empty. If you wish to stop receiving notifications, please use the DeleteSubscription API. |
MISSING_USER | User field must be provided. |
INVALID_USER_RESOURCE_NAME | Invalid user resource name: {userResourceName}. |
INVALID_DATA_TYPE_FORMAT | Data type must be all lowercase: {dataType}. |
INVALID_ARGUMENT | The request is invalid. |
FAILED_PRECONDITION | The request cannot be completed in the current state. |
HTTP 401 (1)
| Reason | Google’s description |
|---|---|
UNAUTHENTICATED | The request is missing valid authentication credentials. |
HTTP 403 (5)
| Reason | Google’s description |
|---|---|
MISSING_OAUTH_SCOPE | Required OAuth scope(s) are missing for this operation. |
DISALLOWED_OAUTH_SCOPES | Request contains disallowed OAuth scope(s): {disallowed_scopes}. Unrecognized scopes present: {unrecognized_scopes_present}. |
API_PRIVATE_PREVIEW_ACCESS_DENIED | User is not eligible for the API Private Preview. |
DATA_ACCESS_DENIED | Data can't be accessed. |
RESOURCE_PERMISSION_DENIED | Permission denied for the requested resource. |
HTTP 404 (1)
| Reason | Google’s description |
|---|---|
RESOURCE_NOT_FOUND | The requested resource was not found. |
HTTP 409 (2)
| Reason | Google’s description |
|---|---|
SLEEP_ALREADY_EXISTS | A sleep log with an overlapping interval already exists. |
ABORTED | The operation was aborted. |
HTTP 429 (1)
| Reason | Google’s description |
|---|---|
RESOURCE_EXHAUSTED | Quota exceeded or rate limited. |
HTTP 500 (1)
| Reason | Google’s description |
|---|---|
INTERNAL_ERROR | An internal error occurred. |
Quoted from Google's v4 error catalog, last updated 2026-10-01, read 2026-10-17.
Google’s troubleshooting tables
400 Bad Request
| Message | Description | Recommendation |
|---|---|---|
| Request contains an invalid argument. | The data type ID {value} is not supported. | Verify the data type being referenced is supported by the endpoint. |
| Invalid JSON payload received. Octal/hex numbers are not valid JSON values. | The dailyRollUp endpoint does not support month and day values represented as MM or DD, respectfully. Single digits shouldn't have a leading 0 (zero). | |
| Your client has issued a malformed or illegal request. | Possible causes: Verify the correct HTTP method is being used Check the endpoint syntax for typos | |
| Invalid project number in resource name | When deleting or updating a subscriber using your Google Cloud project ID in the request URL instead of project number. This applies to webhook subscriptions using the projects.subscribers endpoint. | Use your Google Cloud project number in the request URL, not the project ID. |
| The account is not linked to Google Health. | Status: FAILED_PRECONDITIONReason: ACCOUNT_NOT_LINKEDThe user authorized your app through Google OAuth, but their Google Account does not have an active Google Health profile (either they have never set up Google Health or have not migrated their legacy Fitbit account). | Call users.getIdentity immediately after exchanging the authorization code to verify account linking. If this error occurs, don't mark the account as connected. Instead, prompt the user to sign in to the Google Health mobile app or open the redirect_uri (https://fitbit.google.com/auth/signup). See Handle unlinked Google Accounts. |
Quoted from Google's troubleshooting guide, last updated 2026-09-28, read 2026-10-17.
403 Forbidden
| Message | Description | Recommendation |
|---|---|---|
| The caller does not have permission | When creating or listing subscribers using your Google Cloud project ID in the request URL instead of project number. This applies to webhook subscriptions using the projects.subscribers endpoint. | Use your Google Cloud project number in the request URL, not the project ID. |
| The caller does not have permission. | Could not mint UberMint from GaiaMint. | The user was able to complete the authorization flow, but the endpoint call failed. This can occur when a legacy Fitbit account consents to the app instead of a Google Account. To resolve this error: Sign out of the Google Health app through the settings. Sign into the Google Health app either by pressing the "Continue with Google" or "Sign in with Google" button. If you receive a message that states "Can't use Fitbit with this Google Account", your email address is still registered as a legacy Fitbit account. Follow the steps in this help article to migrate your account. |
Quoted from Google's troubleshooting guide, last updated 2026-09-28, read 2026-10-17.
404 Not Found
| Message | Description | Recommendation |
|---|---|---|
The requested URL /v4/users/me/dataTypes/{dataType}/dataPoints was not found on this server. | Possible causes: Verify the correct verb is being used Check the endpoint syntax for typos |
Quoted from Google's troubleshooting guide, last updated 2026-09-28, read 2026-10-17.
Supporting a user
Retrieve a Fitbit user ID
To help troubleshoot a user issue, you may need to verify the Google Account of the user logged into the Google Health app.
To find the legacy Fitbit user ID:
- Open the Google Health app.
- Press the Health icon in the bottom right hand corner.
- In the "Personal info" section, press Profile.
- In the "Account information" section, the value assigned to the ID is the legacy Fitbit user ID. (For example: CV5TKH)
Quoted from Google's troubleshooting guide, last updated 2026-09-28, read 2026-10-17.
Revoke consent to an app
When helping a user troubleshoot their OAuth2 connection to your app, you may need them to unlink their account from your app and then complete your authorization flow again.
To unlink their Google Account from your app:
- Open the Google Health app.
- Press the user profile icon in the upper right corner.
- Press Apps and services.
- Look for your app name in the list of connected apps, and have the user select it.
- For legacy Fitbit API applications, the "Connected apps" page will appear. Have the user press disconnect under the app name.
- For all other apps, the "Linked apps" page will appear. Have the user find the Google Health API app and select it. Press "Delete all". Have the user press confirm to revoke consent to your app.
When the revoke process completes, the user will be taken back to the list of Third-party apps & services page. The user might need to refresh the page to see the app name removed from the list.
Quoted from Google's troubleshooting guide, last updated 2026-09-28, read 2026-10-17.
Troubleshoot device syncing delays
When debugging issues related to missing or delayed user data, it is helpful to check the user's paired device model and their last synchronization date.
The model information (such as a Fitbit tracker or smartwatch model) and last sync date are useful for troubleshooting and to fetch historical data after syncing delays.
For example, if you notice an unexpected gap or delay in data delivery:
- Verify that the user ID you are querying matches the user ID of the Fitbit account logged into the mobile app. To obtain the user ID in the mobile app, see Retrieve a Fitbit user ID. To obtain the user ID from the access token, call the
getIdentityendpoint. - Check the last sync time to determine when the user's device last synced with the Google Health mobile app.
- If the device has not synced recently, it indicates that the delay is likely due to the device being offline or not syncing with the mobile application, rather than an API issue.
- Once the user opens the mobile application and syncs their device, you can fetch historical data for the period since the last sync time.
To retrieve a user's paired device information, call the users.pairedDevices.list endpoint. This returns a list of devices containing:
deviceVersion: The product name or model of the device (for example, "Charge 6").lastSyncTime: The timestamp of the last successful synchronization.
Quoted from Google's troubleshooting guide, last updated 2026-09-28, read 2026-10-17.
Errors from webhook subscriber calls are on the webhooks page; 429 and quota handling on access and rate limits. The Fitbit Web API’s own errors: Fitbit error code 401.
Questions
What does ACCOUNT_NOT_LINKED mean in the Google Health API?
The user's Google Account is not linked to Google Health yet. If a user completes Google OAuth consent before creating a Google Health profile or before migrating their legacy Fitbit account to their Google Account, calling users.getIdentity or a data endpoint returns an HTTP 400 Bad Request error with status FAILED_PRECONDITION and reason ACCOUNT_NOT_LINKED: Google's fix: Exchange the OAuth authorization code for tokens and immediately call users.getIdentity (GET https://health.googleapis.com/v4/users/me/identity) before marking the account as linked in your app UI. The v4 error catalog's own description of ACCOUNT_NOT_LINKED (HTTP 400) reads: "The Google account is not linked to a Fitbit account."
What does "Could not mint UberMint from GaiaMint" mean in the Google Health API?
Google's troubleshooting guide lists it under 403 Forbidden: The caller does not have permission. — Could not mint UberMint from GaiaMint. — The user was able to complete the authorization flow, but the endpoint call failed. This can occur when a legacy Fitbit account consents to the app instead of a Google Account. To resolve this error: Sign out of the Google Health app through the settings. Sign into the Google Health app either by pressing the "Continue with Google" or "Sign in with Google" button. If you receive a message that states "Can't use Fitbit with this Google Account", your email address is still registered as a legacy Fitbit account. Follow the steps in this help article to migrate your account.
Why does a Google Health API dataPoints request return 404 Not Found?
Google's troubleshooting guide: The requested URL /v4/users/me/dataTypes/{dataType}/dataPoints was not found on this server. — — Possible causes: Verify the correct verb is being used Check the endpoint syntax for typos
Why does a Google Health API subscriber call fail with "Invalid project number in resource name"?
Google's troubleshooting guide: Invalid project number in resource name — When deleting or updating a subscriber using your Google Cloud project ID in the request URL instead of project number. This applies to webhook subscriptions using the projects.subscribers endpoint. — Use your Google Cloud project number in the request URL, not the project ID.
What does SLEEP_ALREADY_EXISTS mean in the Google Health API?
Google's v4 error catalog lists SLEEP_ALREADY_EXISTS with HTTP 409: "A sleep log with an overlapping interval already exists."
Sources checked
- Google Health API Version v4: Error Catalog — last updated 2026-10-01 · read 2026-10-17
- Troubleshooting — last updated 2026-09-28 · read 2026-10-17
- Overview — last updated 2026-09-28 · read 2026-10-17
- Webhook subscriptions — last updated 2026-09-24 · read 2026-10-17
Google’s text is quoted for identification; each guide page’s footer reads: “Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License.”. Generated from Google’s pages by scripts/fetch-google-health-api.mjs, not typed by hand; Google’s documentation remains the authority.