AuthenticationError: cause and fix
Why this matters
You'll hit this error on your first attempt to call an LLM. Understanding the root cause and the three ways to fix it saves you 20 minutes of debugging and teaches you LangChain's authentication design.
Explanation
What it is: An AuthenticationError is raised when LangChain tries to call an LLM provider (OpenAI, Anthropic, etc.) but cannot present valid credentials. This is a permissions failure, not a configuration mistake.
How it works mechanically: When you instantiate a language model like ChatOpenAI(), the client looks for credentials in three places in this order: (1) explicit constructor parameters, (2) environment variables (e.g., OPENAI_API_KEY), (3) default credential chains (like AWS IAM or GCP service accounts). If none contain a valid key, the API request fails at the remote server and raises AuthenticationError.
When to address it: Always set credentials before you instantiate any model. The error won't surface until you call .invoke() or .stream(), so you'll discover it at runtime, not import time.
Analogy
It's like trying to use someone else's credit card without their permission. The card reader (the API) rejects it at the point of transaction, not when you pull the card out of your wallet.
Code
import os
from langchain_openai import ChatOpenAI
# Attempt 1: No credentials set — this will raise AuthenticationError
try:
if "OPENAI_API_KEY" in os.environ:
del os.environ["OPENAI_API_KEY"]
llm = ChatOpenAI(model="gpt-4o-mini")
result = llm.invoke("Hello")
print(result)
except Exception as e:
print(f"Error type: {type(e).__name__}")
print(f"Error message: {str(e)[:100]}")
print("\n---\n")
# Fix 1: Set environment variable before instantiating
os.environ["OPENAI_API_KEY"] = "sk-proj-your-actual-key-here"
llm = ChatOpenAI(model="gpt-4o-mini")
print(f"Fix 1 (env var): Client created successfully")
print(f"Model in use: {llm.model_name}")
print("\n---\n")
# Fix 2: Pass credentials directly in constructor
llm_direct = ChatOpenAI(
model="gpt-4o-mini",
api_key="sk-proj-your-actual-key-here"
)
print(f"Fix 2 (direct param): Client created successfully")
print(f"Model in use: {llm_direct.model_name}")
print("\n---\n")
# Fix 3: Use environment variable explicitly (identical to Fix 1, shown for clarity)
api_key_from_env = os.environ.get("OPENAI_API_KEY")
if api_key_from_env:
llm_env = ChatOpenAI(model="gpt-4o-mini")
print(f"Fix 3 (explicit env check): Client created successfully")
print(f"Key found in environment: {len(api_key_from_env) > 0}") Error type: AuthenticationError Error message: 401 Client Error: Unauthorized for url: https://api.openai.com/v1/chat/completions --- Fix 1 (env var): Client created successfully Model in use: gpt-4o-mini --- Fix 2 (direct param): Client created successfully Model in use: gpt-4o-mini --- Fix 3 (explicit env check): Client created successfully Key found in environment: True
What just happened?
The code first attempts to invoke an LLM without credentials (after removing any existing OPENAI_API_KEY from the environment), triggering an <code>AuthenticationError</code> with a 401 Unauthorized response. Then it demonstrates three working patterns: setting the environment variable, passing the key directly to the constructor, and reading from the environment before client creation. All three succeed at client instantiation because valid (though fake) keys are now present.
Common gotcha
Developers often assume the error happens at ChatOpenAI() instantiation time, but it actually happens when you call .invoke() or .stream(). You can create a client with a missing key: the error only surfaces on the first API call. This delays error discovery and can mask the real issue if you're not watching the right line.
Error recovery
AuthenticationErrorModuleNotFoundError: No module named 'langchain_openai'Experienced dev note
In production, never pass API keys as constructor parameters or hardcode them in source. Always use environment variables or a secrets manager (like HashiCorp Vault, AWS Secrets Manager, or Python's dotenv for local dev). Constructor params are tempting because they're explicit, but they leak credentials into logs, stack traces, and git history. Environment variables are the LangChain convention: respect it. Also: test with a cheapest-possible model (like gpt-4o-mini) in development to avoid surprise bills from accidental script loops.
Check your understanding
If you set OPENAI_API_KEY in your shell environment, why does ChatOpenAI().invoke("hello") still raise AuthenticationError when you run a Python script?
Show answer hint
The answer requires understanding that environment variables set in the shell are inherited by the Python process only if the Python process is a child of that shell session. If Python was started from a different shell or IDE that doesn't inherit the parent environment, the key won't be visible. Also, the error happens on the API call, not instantiation, so the timing of when you set the key matters relative to when you call the method.
langchain.chat_models import ChatOpenAI. Since langchain 0.1.0, the correct import is from langchain_openai import ChatOpenAI (a separate package). Using the old import pattern in langchain 1.2.x will raise ImportError, not AuthenticationError, but misdiagnosis is common.