How to Fix 'invalid API key in production' in LangGraph (Python)

By Cyprian AaronsUpdated 2026-04-21
invalid-api-key-in-productionlanggraphpython

What the error means

invalid API key in production usually means your LangGraph app is running with a missing, stale, or wrong provider key at runtime. In practice, it shows up when your graph invokes an LLM node in a deployed environment and the process cannot read the same environment variables you had locally.

You’ll see this most often after a deploy to Docker, Render, Fly.io, ECS, Kubernetes, or a serverless runtime where OPENAI_API_KEY, ANTHROPIC_API_KEY, or another provider key was never injected correctly.

The Most Common Cause

The #1 cause is loading secrets from a local .env file during development and assuming production will do the same.

That works on your laptop because python-dotenv reads .env. In production, that file usually does not exist, so LangGraph calls into the model client with an empty key and you get errors like:

  • openai.AuthenticationError: Incorrect API key provided
  • anthropic.AuthenticationError: Invalid x-api-key
  • ValueError: API key must be set

Broken vs fixed pattern

BrokenFixed
Loads .env onlyReads real production env vars
Creates model client at import timeCreates client after env is available
Fails silently until graph invocationFails fast with explicit validation
# broken.py
from dotenv import load_dotenv
load_dotenv()  # works locally, often useless in production

from langgraph.graph import StateGraph
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-4o-mini")  # reads OPENAI_API_KEY from env at import time

def call_model(state):
    return {"messages": [llm.invoke(state["messages"])]}

graph = StateGraph(dict)
graph.add_node("model", call_model)
# fixed.py
import os
from langgraph.graph import StateGraph
from langchain_openai import ChatOpenAI

def build_llm() -> ChatOpenAI:
    api_key = os.getenv("OPENAI_API_KEY")
    if not api_key:
        raise RuntimeError("OPENAI_API_KEY is missing in this environment")
    return ChatOpenAI(model="gpt-4o-mini", api_key=api_key)

def call_model(state):
    llm = build_llm()
    return {"messages": [llm.invoke(state["messages"])]}

graph = StateGraph(dict)
graph.add_node("model", call_model)

If you’re using ChatAnthropic, the pattern is identical. The bug is not LangGraph itself; it’s where and how the client gets its credentials.

Other Possible Causes

1) Wrong environment variable name

Different providers expect different keys. If you set API_KEY but your client expects OPENAI_API_KEY, it will fail.

# broken
export API_KEY=sk-...
# fixed
export OPENAI_API_KEY=sk-...

For Anthropic:

export ANTHROPIC_API_KEY=sk-ant-...

2) Key is present locally but not in the deployment runtime

This happens when CI/CD builds pass but runtime containers do not receive secrets.

# docker-compose.yml - broken
services:
  app:
    build: .
    command: python app.py
# docker-compose.yml - fixed
services:
  app:
    build: .
    command: python app.py
    environment:
      OPENAI_API_KEY: ${OPENAI_API_KEY}

In Kubernetes, check that the secret is mounted into the pod environment, not just stored in the cluster.

3) Client initialized before env vars are loaded

If you create the model object at module import time, any later env loading won’t matter.

# broken
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o-mini")

from dotenv import load_dotenv
load_dotenv()  # too late
# fixed
from dotenv import load_dotenv
load_dotenv()

from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o-mini")

Better yet, avoid relying on .env in production entirely.

4) Stale secret after rotation

If you rotated keys in OpenAI or Anthropic and forgot to update your deployment secret store, production will keep sending the old one.

Old key in secret manager:
OPENAI_API_KEY=sk-old123

New key in provider dashboard:
sk-new456

Fix by updating the secret store and restarting the service so the new env var is picked up.

How to Debug It

  1. Print whether the env var exists at runtime

    import os
    print("OPENAI_API_KEY set?", bool(os.getenv("OPENAI_API_KEY")))
    

    If this prints False in production, stop looking at LangGraph code.

  2. Log which provider client you are actually using Make sure your graph node is instantiating the expected class:

    • langchain_openai.ChatOpenAI
    • langchain_anthropic.ChatAnthropic
    • not a custom wrapper pointing to old config
  3. Run a minimal direct client test outside LangGraph

    from langchain_openai import ChatOpenAI
    
    llm = ChatOpenAI(model="gpt-4o-mini")
    print(llm.invoke("ping"))
    

    If this fails with AuthenticationError, your issue is credentials, not graph logic.

  4. Check deployment secrets at runtime In Docker/K8s/serverless platforms, inspect the live container/pod environment. If the secret exists in config but not inside the running process, your deploy wiring is wrong.

Prevention

  • Create a startup check that validates required env vars before building your graph.
  • Keep provider clients inside a factory function if your runtime loads config dynamically.
  • Use separate secret names per provider and per environment:
    • OPENAI_API_KEY_DEV
    • OPENAI_API_KEY_STAGING
    • OPENAI_API_KEY_PROD

If you want this to stay out of incident reports, treat API keys like any other runtime dependency: validate early, inject explicitly, and never assume local .env behavior exists in production.


Keep learning

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

Related Guides