Google Geocoding API: REQUEST_DENIED, OVER_QUERY_LIMIT and ZERO_RESULTS
Every status of the Google Geocoding API with its usual cause and fix, the error_message texts that come with REQUEST_DENIED, and what geocoding costs without Google.
The status field
The Geocoding web service answers HTTP 200 even when a request fails; the result is in the status field, with an optional error_message. Google notes that this message is not always present and that its wording can change, so check status in code and log error_message.
| status | Meaning | Fix |
|---|---|---|
OK | At least one result. | – |
ZERO_RESULTS | The request worked and found nothing. | See below. |
REQUEST_DENIED | The request was rejected. | Read error_message; see below. |
OVER_DAILY_LIMIT | Usually a missing or invalid key, billing that is not set up, a usage cap you set, or a payment method that is no longer valid. | Check the key and billing in Google Cloud. |
OVER_QUERY_LIMIT | A quota is used up. | Slow down, or raise the quota. |
INVALID_REQUEST | Usually address, components or latlng is missing. | Check that the parameter is sent and encoded. |
UNKNOWN_ERROR | A failure at Google. | Try again. |
REQUEST_DENIED and its messages
- “This API project is not authorized to use this API.” The Geocoding API is not enabled in the Google Cloud project of the key. Enable it under APIs & Services; enabling the Maps JavaScript API does not include it.
- “The provided API key is invalid.” The key is mistyped, deleted, or from another project. Copy it again from the credentials page.
- “You must enable Billing on the Google Cloud Project …” Every Google Maps Platform API needs a billing account, also within the free usage.
- “API keys with referer restrictions cannot be used with this API.” A key restricted to websites was sent to the Geocoding web service, which is meant for servers. On a server, use a second key restricted by IP address. In the browser, use the Geocoder class of the Maps JavaScript API with the website key.
- No key at all also gives REQUEST_DENIED. Look at the URL your code sends; an empty environment variable is a common cause.
Changes to keys and restrictions can take a few minutes to apply.
OVER_QUERY_LIMIT
Google allows 3,000 queries a minute per project for the Geocoding API, counting the client side and the server side together, and you can set lower caps yourself. When a quota is reached, the API stops answering until it starts again; daily quotas reset at midnight Pacific time. Spread bulk jobs over time, cache results within what the terms allow, and check the quotas page of the project for a cap set too low.
ZERO_RESULTS
- The address does not exist, or is written in a way Google does not recognise: a missing town, a street name in another language, an apartment or c/o line.
- A
componentsfilter (country, postal code) that contradicts the address. - For reverse geocoding, a point at sea or with
result_typefilters that leave nothing.
What geocoding costs
Since March 2025, Google gives 10,000 free Geocoding requests a month per project and then charges USD 5 per 1,000, with lower prices at high volume. Its terms also limit how long you may keep the results (coordinates for at most 30 days). For a store finder or a list of customer addresses, both add up.
Services on OpenStreetMap data cost less and let you keep the results, at the price of fewer house numbers in some regions. Before switching, geocode a sample of your own addresses with both and compare.
Moving away from Google
The answer formats differ, so the code that reads the result changes. With the Nominatim API of overpass.ch:
// Google: results[0].geometry.location.lat / .lng, results[0].formatted_address const url = "https://api.overpass.ch/v1/YOUR_KEY/nominatim/search?" + new URLSearchParams({ q: address, format: "jsonv2", limit: 1, addressdetails: 1 }); const res = await fetch(url); if (!res.ok) throw new Error((await res.json()).message); const [hit] = await res.json(); if (!hit) console.log("nothing found"); // Google: ZERO_RESULTS else console.log(+hit.lat, +hit.lon, hit.display_name);
import requests
r = requests.get("https://api.overpass.ch/v1/YOUR_KEY/nominatim/search",
params={"q": address, "format": "jsonv2", "limit": 1}, timeout=10)
r.raise_for_status() # errors are HTTP statuses here, not a status field
hits = r.json()
if hits:
print(float(hits[0]["lat"]), float(hits[0]["lon"]), hits[0]["display_name"])
For search as you type, the Photon API on the same data replaces Place Autocomplete. Both are on the geocoding page, with a live demo.
Geocoding from overpass.ch
Search, search as you type and reverse geocoding on OpenStreetMap data. 100'000 requests a month are free, the plans start at a fraction of the Google price, and you may store the results.