Reference
Errors
When a call fails, the answer says what went wrong and what to do next. Here is every error code, and how to handle each one.
What an error looks like
A call that fails answers with an HTTP status and an error object instead of data. This one comes from starting a collection after today's credits ran out:
HTTP/2 429
retry-after: 3600
x-request-id: 7c1e0b54-9a2f-4d3e-8f61-2b5a9c0d4e17{
"error": {
"code": "QUOTA_EXCEEDED",
"message": "You reached your daily limit of 250 credits. Retry after midnight UTC. Buying credits does not raise this limit.",
"messageKey": "serverErrors.quotaDay",
"params": { "limit": 250 },
"details": {
"scope": "day",
"limit": 250,
"resetAt": "2026-09-25T00:00:00.000Z",
"retryAfterSecs": 3600
}
}
}code: what went wrong, as one of the codes below. Codes stay the same while messages can change, so have your program checkcode, notmessage.message: the problem and what to do about it, in English. Log it, or show it to a person.messageKeyandparams: a fixed key and the values that fill it, so an app can show the message in its own language. Most errors carry them.details: more about this error, when there's more to say. For a bad request, it lists the fields that were wrong. For a limit, it says which one and when it resets.
The SDK throws the same fields as a GmapsError, with status, requestId and retryAfter added. Over MCP, a failed tool call comes back with isError: true and this object as its text.
Every error code
Each code always comes with the same HTTP status. The Whose side column says where the problem is: in your request, in your plan's limits, on our side or at Google Maps.
| Code | Status | Whose side | What happened | What to do |
|---|---|---|---|---|
VALIDATION_ERROR | 400 | Yours | Something in the request is missing or wrong. When it's a field, details lists each one with its path. | Fix the request. Sent again as it is, it fails again. |
UNAUTHORIZED | 401 | Yours | The call came without an API key, or not as Authorization: Bearer. | Send your key as Authorization: Bearer gm_…. See Authentication. |
INVALID_TOKEN | 401 | Yours | The key is wrong, revoked or expired, or it's a console sign-in token rather than an API key. | Use an active key, or create a new one under API keys. |
PLAN_GATE | 402 | Your plan | Your plan doesn't include this feature. details.gate names it, and details.upgradeTo names the plan that has it. | Change plans under Plan, then retry. Waiting won't help. |
AUP_REQUIRED | 403 | Yours | Email addresses need your acceptance of the current acceptable use policy, and your account doesn't have it yet. details.version is the version to accept. | Read the policy, accept it in the console under Account, then retry. |
FORBIDDEN | 403 | Yours | Your account can't do this: it's suspended, or you asked to delete it. | The message says which. To stop a deletion, sign in to the console and cancel it. Otherwise, write to support. |
NOT_FOUND | 404 | Yours | There's no such route or id, or it belongs to another account. | Check the method, the URL and the id. |
PLACE_NOT_FOUND | 404 | Yours | We haven't saved this place, or we removed it after a removal request. | Search its area to collect it, then look it up again. A removed place won't come back. See Places. |
COLLECTION_NOT_FOUND | 404 | Yours | Your account has no collection with this id. | Check the id. GET /v1/collections lists yours. |
EXPORT_NOT_FOUND | 404 | Yours | The export link is more than 24 hours old, its collection's places were deleted, or the link is wrong. | Create a new export. If the collection is more than 30 days old, run it again first. |
CONFLICT | 409 | Yours | The call clashes with how things stand now, such as cancelling a collection that already ended, or creating a key past your plan's limit. | The message says what's in the way. Change that, then retry. |
PAYLOAD_TOO_LARGE | 413 | Yours | The request body is larger than we accept. params.limit is the most, in bytes. | Send a smaller body. |
GEO_UNRESOLVED | 422 | Yours | We couldn't find the city you gave, or more than one city has that name. Only Brazilian cities work by name. | Add the state, like Curitiba, PR, or pick one from details.candidates. Outside Brazil, send lat, lng and radiusM, or a bbox. |
UPSTREAM_BLOCKED | 422 | Google Maps | We don't send this yet. It's kept for when Google Maps refuses our searches. Today, a collection whose searches fail ends with ENGINE_UNAVAILABLE instead. | Nothing, for now. If you handle it anyway, try again later with a smaller area. |
RATE_LIMIT_EXCEEDED | 429 | Your plan | Your account made more calls this minute than your plan allows. | Wait the number of seconds in retry-after, then retry. details.limit is how many calls the limit allows, and details.window is how long it counts them: minute, or hour for the removal form. |
QUOTA_EXCEEDED | 429 | Your plan | You're out of credits for today or this month, or running as many collections as your plan allows. details.scope says which. | It depends on details.scope. See the next section. |
INTERNAL_ERROR | 500 | Ours | Something broke on our side. | Retry. If it keeps failing, write to support with the x-request-id. |
ENGINE_UNAVAILABLE | 503 | Ours | We couldn't run a collection's searches, so it found nothing and charged nothing. You see this on the collection's error, not as a failed call. | Start the collection again in a few minutes. Searches still answer with the places we saved. |
SERVICE_UNAVAILABLE | 503 | Ours | A service we depend on, such as our database, didn't answer. | Retry after a few seconds. If it keeps failing, write to support. |
BILLING_UNAVAILABLE | 503 | Ours | We couldn't reach our payment provider, or payments aren't set up yet. Only the console's Plan page runs into this, never the API. | Try again later. Nothing was charged. |
Plan features and limits
Only PLAN_GATE answers 402. It means your plan doesn't include the feature, so waiting won't change the answer. details.upgradeTo names the cheapest plan that has it. Switch under Plan, then retry.
Using up a limit answers 429, and waiting clears it. RATE_LIMIT_EXCEEDED means too many calls this minute. QUOTA_EXCEEDED is about credits or collections, and details.scope says which:
month: this month's credits are spent, pack credits included.details.resetAtis the 1st of next month at midnight UTC. A credit pack lets you go on right away.day: you reached today's limit.details.resetAtis the next midnight UTC. A pack doesn't raise it.concurrency: you're running as many collections as your plan allows. Try again when one ends. This one has noresetAt.
Limits has every number for every plan.
When to try again
- When the answer has a
retry-afterheader, wait that many seconds, then send the same call again.RATE_LIMIT_EXCEEDEDalways has it, and so doesQUOTA_EXCEEDEDfordayandmonth. The same number is indetails.retryAfterSecs. - Any other 4xx: fix what the message names first. Sent again as it is, the call usually gets the same answer.
- A 5xx is on our side. Try again after a few seconds, and wait a little longer after each failure. The SDK doesn't retry for you.
Asking us for help
Every answer, errors included, carries an x-request-id header. It points to that one call in our logs. When you write to support, send it along with what you sent and when.
You can also send your own x-request-id, such as the id your logs already use, so one id follows the call from your logs into ours. Use up to 64 letters, digits, dots, dashes and underscores, and nothing else. Otherwise we make a new one.
Never send us your API key. We don't need it to find the call.