Gemini API 400 INVALID_ARGUMENT, FAILED_PRECONDITION and "API key not valid"
A Gemini call returns HTTP 400 before generating anything. The body says which kind: a bad key (Gemini reports that as 400, not 401), a missing prerequisite, or a request the API won't accept. Below are the fixes for each, plus the OpenAI-compatibility differences that cause 400s.
Quick answer
Read error.status and error.message. API key not valid. Please pass a valid API key. (reason API_KEY_INVALID) means the key is wrong, has stray whitespace, or a stale GOOGLE_API_KEY is overriding GEMINI_API_KEY. FAILED_PRECONDITION means a prerequisite is missing, usually billing in a region without a free tier. Any other INVALID_ARGUMENT is a request-shape problem: a typo, a v1beta feature on /v1, or a parameter newer models reject. A 400 won't succeed on retry, so fix the request first.
Symptoms and What the Error Means
The bad-key case, exactly as Google's generateContent error reference shows it:
{
"error": {
"code": 400,
"message": "API key not valid. Please pass a valid API key.",
"status": "INVALID_ARGUMENT",
"details": [
{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "API_KEY_INVALID",
"domain": "googleapis.com",
"metadata": { "service": "generativelanguage.googleapis.com" }
},
{
"@type": "type.googleapis.com/google.rpc.LocalizedMessage",
"locale": "en-US",
"message": "API key not valid. Please pass a valid API key."
}
]
}
}The same reference lists the other two 400s:
| Status | Documented message / cause | What to do |
|---|---|---|
INVALID_ARGUMENT | "The request body is malformed": a typo, a missing required field, or a newer-version feature on an older endpoint | Compare the body with the API reference; the message usually names the field |
FAILED_PRECONDITION | "Gemini API free tier is not available in your country. Please enable billing on your project in Google AI Studio." | Link a Cloud Billing account to the project |
On the newer Interactions API, the same problems show up as code values: invalid_request (malformed payload), parameter_unknown (remove the unrecognized parameter), and failed_precondition (for example, billing disabled). All three come back as HTTP 400.
Nearby errors that need a different fix:
- 403
PERMISSION_DENIED: the key is blocked or leaked (Your API key was reported as leaked. Please use another API key.), or the project needs verification, is restricted, or has a billing problem. See Google's troubleshooting guide. - 429
RESOURCE_EXHAUSTED: the request is fine, but the project went over a quota. See Gemini API 429 RESOURCE_EXHAUSTED.
Why It Happens
- The key check runs before anything else, and an invalid key comes back as
INVALID_ARGUMENT. So clients that only treat 401 as an auth error will miss it. - Environment variable precedence. Per Google's API key guide, the client libraries read
GEMINI_API_KEYorGOOGLE_API_KEY, and if both are set,GOOGLE_API_KEYtakes precedence. An oldGOOGLE_API_KEYleft over from another Google project quietly replaces the key you just set. - Key types are changing. New AI Studio keys created since May 28, 2026 are authorization keys, and the Gemini API rejects unrestricted standard keys; restricted standard keys keep working.
- Newer models reject parameters older ones accepted. Starting with Gemini 3.6 Flash, Google's API changes apply to all later models, which tightens what a valid request looks like.
Fix 1: Prove the Key Works, in Isolation
# 1. Which keys will the SDK see? GOOGLE_API_KEY wins if both are set.
env | grep -E 'GOOGLE_API_KEY|GEMINI_API_KEY'
# 2. Check for invisible characters: the last bytes should not include \n or spaces
printf '%s' "$GEMINI_API_KEY" | tail -c 3 | od -c
# 3. Quickest key check: list models
curl -sS "https://generativelanguage.googleapis.com/v1beta/models" \
-H "x-goog-api-key: $GEMINI_API_KEY" | head -20If step 3 returns API_KEY_INVALID, the key itself is the problem: create a fresh one on the AI Studio API Keys page and replace it everywhere. If step 3 succeeds but generation still fails, keep going. Google notes that models.list "only validate[s] that your API key exists" and doesn't check tier eligibility or billing, so test a real call:
curl -sS "https://generativelanguage.googleapis.com/v1beta/models/gemini-3.8-flash:generateContent" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"contents": [{"parts": [{"text": "Reply with: ok"}]}]}'Other key mix-ups to rule out:
- A key from another service. A gateway token or an OpenAI key sent to
generativelanguage.googleapis.comis "not valid". The same goes the other way: a Google key won't work on a gateway. - An older standard key that suddenly fails. In the Cloud console, check that it is restricted (for example to the Generative Language API); unrestricted standard keys are rejected.
Fix 2: Fix the Request Shape
For a generic INVALID_ARGUMENT, the message usually names the field. Common causes:
- Typos and wrong nesting.
contents→parts→textis the minimal structure. Generation settings go undergenerationConfig, not at the top level. - API version mismatch. Google says beta features "will only be available in the
/v1betaAPI version", and that using newer-version features on an older endpoint causes errors. If a field is documented but rejected, check whether your URL says/v1/where it should say/v1beta/. - Output length.
maxOutputTokensmust be within the model's limit. Check the models page for each model's maximum. - Structured output. Google documents that response schemas "too complex to enforce (for example, large
maxItemson nested arrays) return a 400 INVALID_ARGUMENT error." Flatten the schema or check those limits in code.
Fix 3: Update Parameters for Gemini 3.6+ and Gemini 4
If you upgraded the model ID and kept the old request, these rules are the usual cause:
| Parameter | Rule on current models | Action |
|---|---|---|
Prefilled model turn (last non-empty turn is model) | Returns 400 from Gemini 3.6 Flash onward | End the request with a user turn |
candidateCount | Unsupported on Gemini 3 and 4 | Remove it; send separate requests for multiple samples |
temperature, topP, topK | Deprecated and ignored on Gemini 3.6+ and 4; Google says they'll return 400 in future model generations | Remove them now |
| Thought signatures | On Gemini 3 and 4, you must pass them back during function calling, or you get a 4xx validation error | Append the model's full response, signatures included, to history; the official SDKs do this automatically |
Hand-written agent loops that rebuild history from just the function name and arguments lose the signature. Google's thought signatures guide has the exact turn-by-turn shapes, including the OpenAI-compatible variant.
Fix 4: Resolve FAILED_PRECONDITION
The documented case is the free tier being unavailable where you are. The fix is to set up billing and link a Cloud Billing account to the project. Creating new keys or retrying doesn't help, because Google decides free-tier eligibility per project. Some models need billing anyway: Google states that Gemini 4 Argon "is not available on the Free tier."
Fix 5: OpenAI Compatibility Layer Differences
Google's OpenAI compatibility endpoint lets the OpenAI SDKs call Gemini, but it isn't a full copy of the OpenAI API. Google labels it beta. These differences cause most 400s there:
from openai import OpenAI
client = OpenAI(
api_key="GEMINI_API_KEY", # a Gemini key, sent as Authorization: Bearer
base_url="https://generativelanguage.googleapis.com/v1beta/openai/",
)
resp = client.chat.completions.create(
model="gemini-3.8-flash",
messages=[{"role": "user", "content": "Explain how AI works"}],
# Either reasoning_effort ...
reasoning_effort="low",
# ... OR Gemini's own thinking_config, never both:
# extra_body={"extra_body": {"google": {"thinking_config": {"thinking_level": "high"}}}},
)reasoning_effortandthinking_configcan't be combined. Google: they "overlap functionality, so they can't be used at the same time."- Reasoning effort is mapped, not passed through. For Gemini 4,
minimalmaps tolow, andxhighis listed forgemini-4-hydrogenonly. Reasoning can't be turned off for Gemini 3 or Gemini 4 models;"none"only works on 2.5 models. - Gemini-only features go in
extra_body. In the Python SDK, Google's examples nest it twice,extra_body={"extra_body": {"google": {...}}}, withcached_contentorthinking_configinside. The OpenAI Python SDK rejects keyword arguments it doesn't know, which is why Gemini fields go there. - Image generation drops unknown parameters. On the images endpoint, parameters beyond the documented set are "silently ignored", so a missing effect there won't show up as a 400.
- Log the raw body, not just the SDK's exception class: the
messagenames the field that failed.
For model-ID mistakes on any OpenAI-compatible endpoint, see Model not found 404. The same "copy the ID from the model list" rule applies to Gemini.
If You're Using byesu
byesu is an AI API gateway with an OpenAI-compatible endpoint: one key for Gemini, Claude, GPT and Grok, billed pay-as-you-go with no subscription. Two notes:
- Gemini through
https://byesu.com/v1. Use the OpenAI SDK with yoursk-token and model IDsgemini-4-argonorgemini-3.8-flash. Your Google key isn't used there, soAPI_KEY_INVALIDand free-tierFAILED_PRECONDITIONerrors don't apply. Model-level rules, such as no prefilled final assistant turn, still do. - Errors come back in OpenAI format. A rejected request returns an OpenAI-style
{"error": {"message": ..., "type": ..., "code": ...}}body instead of Google'sstatusanddetails, so readerror.messagefor the field that failed.
To get started, create a token in the console and follow the Quick Start.
FAQ
Why does Gemini return API key not valid. Please pass a valid API key?
The key in your request is not a key the Gemini API accepts. It returns HTTP 400 with status INVALID_ARGUMENT and reason API_KEY_INVALID. Common causes are a typo or stray whitespace, a stale GOOGLE_API_KEY overriding GEMINI_API_KEY (GOOGLE_API_KEY wins when both are set), or sending a key from another service.
What does 400 FAILED_PRECONDITION mean on the Gemini API?
A prerequisite for the request is not met. The documented case is "Gemini API free tier is not available in your country. Please enable billing on your project in Google AI Studio." Linking a Cloud Billing account to the project in AI Studio resolves it; retrying does not.
What causes a generic Gemini 400 INVALID_ARGUMENT?
A malformed request body: a typo or missing required field, a feature used on the wrong API version (v1 instead of v1beta), or a parameter the model no longer accepts. On Gemini 3.6 and later, a prefilled model turn returns 400, candidate_count is unsupported, and temperature, top_p and top_k are deprecated. The error message usually names the field.
Can I use reasoning_effort and thinking_config together in Gemini OpenAI compatibility?
No. Google documents that reasoning_effort and thinking_level or thinking_budget overlap, so they cannot be used at the same time. Send either reasoning_effort, or a thinking_config inside extra_body, not both. Reasoning cannot be turned off for Gemini 3 or Gemini 4 models.
Does a 200 from models.list mean my Gemini key works?
Only partly. Google notes that models.list checks that the key exists but does not check project tier eligibility or billing status, so generateContent can still fail. It is still a useful first test: if models.list itself returns API_KEY_INVALID, the key is the problem.
