"Nothing in my code changed, but the day after I bumped the SDK my app started crashing with API key not valid." This is one of the quieter, more frustrating traps you hit in your first month with the Gemini API. The cause is usually not the key itself — it is which environment variable the SDK is reading. GEMINI_API_KEY and GOOGLE_API_KEY look interchangeable, but every library has its own opinion about which one wins.
I personally lost two hours to this when I ported one of my side-project tools from Python to Node.js. This article maps out the precedence rules across the SDKs you are most likely to mix, the conditions that flip your client into Vertex AI mode, and the four traps that catch real developers — with a five-minute diagnostic snippet you can paste into any app to find out exactly which path is active.
Why two variable names exist in the first place
The Gemini SDK has gone through generations, and each generation set a different convention.
The legacy google-generativeai library, dominant through early 2024, did not read environment variables automatically. You configured it explicitly with genai.configure(api_key=...), and most developers fell into the habit of naming the variable GOOGLE_API_KEY because that matched the rest of Google Cloud.
The current google-genai library, the official replacement from late 2024 onward, formally adopted GEMINI_API_KEY as its primary name. For backward compatibility it still reads GOOGLE_API_KEY, but GEMINI_API_KEY wins when both are set. On top of that, setting GOOGLE_GENAI_USE_VERTEXAI=true quietly disables the API-key path entirely and switches the client to Application Default Credentials (ADC).
Add LangChain and the Vercel AI SDK — each with their own preferred variable names — and you end up with three coexisting worlds. That is the whole story behind the confusion.
Precedence cheat sheet by SDK
Here is how the most common libraries actually resolve the key.
- google-genai (Python and Node.js): explicit
api_keyargument >GEMINI_API_KEY>GOOGLE_API_KEY. If both env vars are set, the first one wins. - google-genai in Vertex mode: when
GOOGLE_GENAI_USE_VERTEXAI=trueis set, API keys are ignored entirely. Authentication switches to ADC, and you must also haveGOOGLE_CLOUD_PROJECTandGOOGLE_CLOUD_LOCATIONset. - google-generativeai (legacy Python SDK): no automatic env reading. You must pass it yourself:
genai.configure(api_key=os.getenv("GOOGLE_API_KEY")). - LangChain
langchain-google-genai: expectsGOOGLE_API_KEY. Setting onlyGEMINI_API_KEYproduces a confusing "Invalid API key" error because LangChain never reads it. - Vercel AI SDK
@ai-sdk/google: looks forGOOGLE_GENERATIVE_AI_API_KEY. A third name, distinct from both of the above.
The takeaway is that the same valid key may need to live under different names depending on which library is consuming it.
A five-minute diagnostic snippet
When authentication breaks, the first thing to confirm is which variables your process can actually see. Drop these four lines at the top of your Python entrypoint and the cause becomes obvious.
import os
# Print which key-related env vars are visible to this process at startup.
print("GEMINI_API_KEY:", "set" if os.getenv("GEMINI_API_KEY") else "missing")
print("GOOGLE_API_KEY:", "set" if os.getenv("GOOGLE_API_KEY") else "missing")
print("GOOGLE_GENAI_USE_VERTEXAI:", os.getenv("GOOGLE_GENAI_USE_VERTEXAI"))
print("GOOGLE_APPLICATION_CREDENTIALS:", os.getenv("GOOGLE_APPLICATION_CREDENTIALS"))A healthy output for the API-key path looks like this:
GEMINI_API_KEY: set
GOOGLE_API_KEY: missing
GOOGLE_GENAI_USE_VERTEXAI: None
GOOGLE_APPLICATION_CREDENTIALS: None
If you see GOOGLE_GENAI_USE_VERTEXAI: true, your client is in Vertex mode. API keys are ignored and the SDK is trying ADC. If you have not run gcloud auth application-default login locally, you will get a 403 every time, no matter how correct your key is.
To confirm which path the new SDK actually took, peek at the client's internal state right after construction:
from google import genai
client = genai.Client()
print("vertexai mode:", client._api_client.vertexai)
print("api_key present:", bool(client._api_client.api_key))vertexai mode: False plus api_key present: True means the API-key path is active. vertexai mode: True means you are on ADC. You can stop guessing.
If your project is Node.js or TypeScript, the equivalent diagnostic is just as short. Place it before any SDK import to make sure the values you see match what the library will read.
// Node.js / TypeScript: print env state before any SDK initialization.
console.log("GEMINI_API_KEY:", process.env.GEMINI_API_KEY ? "set" : "missing");
console.log("GOOGLE_API_KEY:", process.env.GOOGLE_API_KEY ? "set" : "missing");
console.log("GOOGLE_GENAI_USE_VERTEXAI:", process.env.GOOGLE_GENAI_USE_VERTEXAI ?? "unset");
console.log("GOOGLE_APPLICATION_CREDENTIALS:", process.env.GOOGLE_APPLICATION_CREDENTIALS ?? "unset");In serverless platforms — Vercel, Netlify, Cloudflare — these process.env reads return undefined for variables you forgot to register on the dashboard, even when they exist in your local .env.local. Seeing missing in the logs of a deployed function points you straight at the platform's environment variable settings rather than at the SDK.
Four traps that catch real developers
Once you know which variable is being read, the actual fixes fall out quickly. Here are the four patterns I see most often.
1. You set GOOGLE_API_KEY in .env.local, but the new SDK still returns 403. Check whether GOOGLE_GENAI_USE_VERTEXAI=true is leaking in from somewhere else — a Docker base image, a CI shell profile, or an old direnv block. unset GOOGLE_GENAI_USE_VERTEXAI clears it. If you never want Vertex mode in this project, write GOOGLE_GENAI_USE_VERTEXAI=false explicitly so a stray true upstream cannot reactivate it silently.
2. python-dotenv is not overriding what is in your shell. By default it does not overwrite values that already exist in the process environment. If your shell still has an old GOOGLE_API_KEY from last week, your fresh .env is being shadowed. Pass load_dotenv(override=True) or open a clean shell session.
3. LangChain throws "Invalid API key" while everything else works. LangChain reads GOOGLE_API_KEY, not GEMINI_API_KEY. Either set both, or inject the value explicitly: ChatGoogleGenerativeAI(google_api_key=os.getenv("GEMINI_API_KEY")). The latter is more explicit and survives future name changes.
4. Cloudflare Workers or Pages: it works locally but 401 in production. Workers do not read .env files. Register the key as a secret with wrangler secret put GEMINI_API_KEY, or — only for non-sensitive values — add it under [vars] in wrangler.toml. Anything in vars ships in plain text, so production keys belong on the secret side.
Where each platform expects you to put the key
Even with the SDK precedence sorted out, every deployment platform has its own loading model. Skipping these details is the second-largest cause of "works locally, breaks in production" auth bugs after the variable-name mismatch above.
- Vercel: dashboard → Project Settings → Environment Variables. Vercel scopes variables to Production, Preview, and Development separately, so a key set only for Production silently disappears in
vercel dev. If you use the Vercel AI SDK on top ofgoogle-genai, setGOOGLE_GENERATIVE_AI_API_KEYfor the AI SDK andGEMINI_API_KEYfor the underlying client both — the AI SDK reads the former, anything you call directly reads the latter. - Netlify: dashboard → Site Configuration → Environment Variables. Netlify Build and Netlify Functions share the same scope, but local
netlify devonly injects values when you opt in withnetlify env:get. A common surprise is that Edge Functions run in a different runtime whereprocess.envis replaced byNetlify.env.get("GEMINI_API_KEY"). - Cloudflare Workers / Pages:
wrangler secret put GEMINI_API_KEYfor sensitive values,[vars]inwrangler.tomlfor non-sensitive defaults. Workers expose values on theenvparameter (env.GEMINI_API_KEY), not onprocess.env. Code copied from a Vercel project will silently readundefinedon Workers becauseprocess.envis essentially empty in a Workers runtime. - AWS Lambda: configure as Lambda environment variables, or use AWS Secrets Manager for production. If you mount Secrets Manager values via the Parameters and Secrets Lambda Extension, they appear as files at
/tmp/..., not as env vars — a subtle gotcha for anyone expectingprocess.env.GEMINI_API_KEYto be populated automatically. - Google Cloud Run: when you deploy from source,
gcloud run deploy --set-env-vars=GEMINI_API_KEY=...is the most reliable path. For Vertex mode, you typically want--set-env-vars=GOOGLE_GENAI_USE_VERTEXAI=true,GOOGLE_CLOUD_LOCATION=us-central1instead, with the API key omitted entirely.
The pattern in all five is the same: the platform owns environment injection, and the SDK only sees what was actually injected. Always print the diagnostic snippet from the previous section in your real deployment logs at least once after a deploy, before you start chasing imaginary SDK bugs.
Three operating rules for a calmer life
When you run multiple environments — local, CI, staging, production, plus side projects — these three rules dramatically cut auth incidents.
Rule 1: Log the auth path on startup. Drop the four os.getenv lines into your main.py so every process announces which variables are visible. Never log the key value itself; set versus missing is enough to triage.
Rule 2: Standardize on GEMINI_API_KEY for new projects. It is the official name, and it visually distinguishes Gemini keys from generic Google Cloud API keys. Keep GOOGLE_API_KEY only in legacy systems where renaming would touch too many call sites. Avoid mixing both within a single service.
Rule 3: Use the same variable name in CI and production. Environment-name drift is the single biggest cause of "works on my machine" auth bugs. Pin one name per service and write it down in an ENV.md at the repo root — your future self, three months from now, will thank you.
For the broader setup story, the Google AI Studio API key setup and management guide and the Gemini API authentication error solutions article cover provisioning and the failure modes around it. If you are migrating between SDK generations, the google-genai Python SDK migration guide is the natural next stop.
Open the .env of whichever project you are touching today, say out loud which variable name is in use, and you will already be in better shape than most teams the next time you bump the SDK.