How to Fix 'invalid API key in production' in LangChain (Python)
When LangChain says invalid API key in production, it usually means your app is not sending the key you think it is. In practice, this shows up after deployment when local .env loading works, but the production runtime has a missing, stale, malformed, or wrong-provider key.
The error often appears when instantiating ChatOpenAI, OpenAIEmbeddings, or any other LangChain wrapper that calls an external LLM API. The key point: LangChain is rarely the problem; your environment wiring is.
The Most Common Cause
The #1 cause is loading environment variables locally with load_dotenv() and assuming production will have the same setup.
In development, this works because .env exists on disk. In production, your container, serverless runtime, or process manager may not load that file at all.
Broken vs fixed pattern
| Broken pattern | Fixed pattern |
|---|---|
Relies on .env at runtime | Uses real environment variables from the deployment platform |
| Instantiates clients before env is loaded | Loads config before creating LangChain objects |
| Fails silently until first request | Fails fast if the key is missing |
# broken.py
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o-mini") # reads env too early
load_dotenv() # too late for already-created objects
response = llm.invoke("Hello")
print(response.content)
# fixed.py
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
load_dotenv() # local dev only; production should inject env vars
api_key = os.getenv("OPENAI_API_KEY")
if not api_key:
raise RuntimeError("OPENAI_API_KEY is missing")
llm = ChatOpenAI(
model="gpt-4o-mini",
api_key=api_key,
)
response = llm.invoke("Hello")
print(response.content)
If you are using ChatOpenAI, the failure in logs often looks like one of these:
- •
openai.AuthenticationError: Error code: 401 - {'error': {'message': 'Incorrect API key provided'}} - •
openai.AuthenticationError: Invalid authentication credentials - •
langchain_core.exceptions.OutputParserExceptionlater in the chain if the model call failed upstream
The fix is to make sure the production process gets the real key before Python starts handling requests.
Other Possible Causes
1. Wrong environment variable name
LangChain wrappers look for provider-specific variables. For OpenAI, use OPENAI_API_KEY, not API_KEY or LANGCHAIN_API_KEY.
# broken
os.environ["API_KEY"] = "sk-..."
llm = ChatOpenAI(model="gpt-4o-mini")
# fixed
os.environ["OPENAI_API_KEY"] = "sk-..."
llm = ChatOpenAI(model="gpt-4o-mini")
2. Key injected into the wrong process
This happens a lot with Gunicorn, Uvicorn, Docker, and systemd. The shell where you tested has the variable, but the running service does not.
# broken: set in your shell only
export OPENAI_API_KEY=sk-...
gunicorn app:app # maybe not inheriting what you expect in prod
# fixed: set in deployment config or container env
docker run -e OPENAI_API_KEY=sk-... my-app
For Kubernetes:
env:
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: openai-secret
key: api_key
3. Using a revoked or rotated key
A valid-looking string can still fail if it was rotated in the provider dashboard.
llm = ChatOpenAI(
model="gpt-4o-mini",
api_key="sk-oldrevokedkey123"
)
Fix by verifying the active secret in your vault or secret manager and redeploying after rotation.
4. Mixing providers and keys
This happens when you use an Anthropic or Azure OpenAI endpoint with an OpenAI key, or vice versa. LangChain classes are provider-specific.
# broken: OpenAI key with Azure client settings mismatch
from langchain_openai import AzureChatOpenAI
llm = AzureChatOpenAI(
azure_deployment="my-deployment",
api_key=os.getenv("OPENAI_API_KEY"), # wrong source in many setups
azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"),
)
# fixed: use the correct provider secret and config
llm = AzureChatOpenAI(
azure_deployment="my-deployment",
api_key=os.getenv("AZURE_OPENAI_API_KEY"),
azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"),
api_version="2024-02-15-preview",
)
How to Debug It
- •
Print exactly what your process sees Check whether the variable exists at runtime, not just in your terminal.
import os print(repr(os.getenv("OPENAI_API_KEY"))) - •
Verify object creation order Make sure you load env vars before creating
ChatOpenAI,AzureChatOpenAI, or embeddings classes. If initialization happens at module import time, move it behind app startup code. - •
Test outside LangChain Call the provider SDK directly with the same key. If raw SDK auth fails, LangChain is innocent.
from openai import OpenAI client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) print(client.models.list()) - •
Check deployment secrets and logs Compare local
.env, CI secrets, container env vars, and cloud secret manager values. Look for:- •trailing spaces in secrets
- •old rotated keys still mounted in pods
- •wrong secret name in Helm/Terraform/serverless config
Prevention
- •Load configuration from environment variables injected by your platform, not from
.envfiles in production. - •Fail fast on startup if required secrets are missing.
- •Keep provider keys isolated by service:
- •
OPENAI_API_KEY - •
ANTHROPIC_API_KEY - •
AZURE_OPENAI_API_KEY
- •
If you want to avoid this class of issue entirely, treat API keys as deployment-time inputs and validate them before constructing any LangChain client. That gives you a clean startup failure instead of a noisy runtime incident.
Keep learning
- •The complete AI Agents Roadmap — my full 8-step breakdown
- •Free: The AI Agent Starter Kit — PDF checklist + starter code
- •Work with me — I build AI for banks and insurance companies
By Cyprian Aarons, AI Consultant at Topiax.
Want the complete 8-step roadmap?
Grab the free AI Agent Starter Kit — architecture templates, compliance checklists, and a 7-email deep-dive course.
Get the Starter Kit