Every engineer who has shipped a LangChain app has stared at a cryptic stack trace. The common langchain error messages usually fall into a handful of categories: misconfigured credentials, broken model bindings, malformed prompts, and output parsing mismatches. This guide walks through the ones you’ll hit first and gives an ordered path to fix them without guesswork.
LangChain versions matter. The examples below target langchain 0.1.x and openai 1.x. Error classes moved from openai.error to top-level openai exceptions in the 1.0 SDK, so the same root cause now raises a different type than it did a year ago.
1. Authentication and API key errors
The first wall you hit is almost always credentials. LangChain does not invent its own auth layer; it passes keys to the underlying SDK. If OPENAI_API_KEY is missing, ChatOpenAI() raises a ValueError before any network call:
from langchain.chat_models import ChatOpenAI
# Raises: ValueError: You must pass an openai_api_key or set OPENAI_API_KEY env var.
llm = ChatOpenAI()
The fix is boring but strict: load from environment, never hardcode. Use python-dotenv and fail fast at startup.
import os
from dotenv import load_dotenv
load_dotenv()
assert os.getenv("OPENAI_API_KEY"), "OPENAI_API_KEY not set"
If you see openai.AuthenticationError instead of ValueError, you are on openai>=1.0 and LangChain forwarded the SDK error. The remedy is identical.
A subtler pitfall is using the wrong class for the provider. OpenAI (completions) vs ChatOpenAI (chat) both read the same env var but send different request shapes. If you swap them, you get InvalidRequestError about model compatibility, not an auth error. Keep your imports explicit and pin langchain and openai versions together in your lockfile.
2. Model not found or unsupported parameters
After auth, the next tier of common langchain error messages comes from model routing. A typo in model_name surfaces as NotFoundError or InvalidRequestError:
llm = ChatOpenAI(model_name="gpt-4-turbo-preview") # fine
llm = ChatOpenAI(model_name="gpt-4-trubo") # InvalidRequestError: model does not exist
With Azure OpenAI, the parameter is deployment_name, not model_name. Using the wrong one yields a 404 that LangChain wraps as ValueError: Unable to infer model name. Read the provider docs; don’t assume the OpenAI signature transfers.
Parameter validation also bites. temperature=2.0 is out of range for most models. Pydantic in LangChain will raise ValidationError at construction:
ChatOpenAI(temperature=2.0) # ValidationError: ensure this value is less than or equal to 1.0
Passing arbitrary model_kwargs can trigger a provider-side reject. This works:
ChatOpenAI(model_kwargs={"top_p": 0.9})
But {"frequency_penalty": "high"} raises InvalidRequestError because the type is wrong. Tradeoff: strict validation catches bugs early but blocks dynamic config from env vars. If you load parameters from a string, cast and clamp before passing.
3. Rate limits and provider degradation
Once the code runs, throughput exposes the next class of common langchain error messages: RateLimitError and APIConnectionError. In a dev loop, a forgotten for over 100 prompts will trip the 60k TPM limit fast.
from openai import RateLimitError
from langchain.chat_models import ChatOpenAI
llm = ChatOpenAI(max_retries=3, request_timeout=30)
try:
llm.invoke("Summarize this")
except RateLimitError as e:
# log, backoff, or degrade
print(f"Rate limited: {e.status_code}")
The max_retries uses exponential backoff from the OpenAI SDK. But retries are not infinite. If you route through a gateway such as n4n.ai, automatic fallback when a provider is rate-limited or degraded can mask these errors, but your code should still catch RateLimitError to log and shed load.
APIConnectionError often points to a proxy or DNS issue, not the model. Set request_timeout explicitly; the default can hang in constrained networks. Pitfall: catching Exception broadly hides the root cause. Catch the specific SDK error and let unknown ones propagate.
4. Prompt template and input validation errors
Prompt construction fails loudly when variables mismatch. PromptTemplate.from_template infers input_variables from {braces}. Call .format() with the wrong keys and you get a KeyError:
from langchain.prompts import PromptTemplate
prompt = PromptTemplate.from_template("Write a {style} poem about {topic}")
prompt.format(topic="rust") # KeyError: 'style'
The fix is to declare variables explicitly and validate at build time:
prompt = PromptTemplate(input_variables=["style", "topic"], template="Write a {style} poem about {topic}")
A common tradeoff: loose templates with .from_template are faster to write but blow up at runtime. Explicit input_variables shift the check to import time. In a large app, I prefer the latter.
Escaping braces is another silent killer. If your prompt contains literal { for JSON schema, double them: {{"key": "value"}}. Forgetting this raises KeyError on the inner quotes. With FewShotPromptTemplate, mismatched example keys vs input_variables raise ValueError at construction—catch it in tests.
5. Output parser exceptions
The most frustrating of the common langchain error messages is OutputParserException. You asked for JSON, the model returned prose. With PydanticOutputParser, a missing field raises:
from langchain.output_parsers import PydanticOutputParser
from pydantic import BaseModel
class Answer(BaseModel):
score: int
rationale: str
parser = PydanticOutputParser(pydantic_object=Answer)
# If LLM output is "Score: 5, Reason: good", parser.parse throws OutputParserException
Two fixes. First, always inject parser.get_format_instructions() into the prompt. Second, use OutputFixingParser to ask the model to repair its own output:
from langchain.output_parsers import OutputFixingParser
fixing_parser = OutputFixingParser.from_llm(parser=parser, llm=ChatOpenAI())
result = fixing_parser.parse(bad_output)
Cost tradeoff: the fix step is an extra LLM call. In high-volume pipelines, strict parsing with a cheap retry is better than a fix call per failure. For CommaSeparatedListOutputParser, a single stray comma breaks splitting—preprocess the raw text or use EnumOutputParser when the domain is closed.
6. Retriever and vector store errors
RAG chains fail at the data layer. Chroma without a persistence dir loses collections on exit, then get_retriever() returns empty results silently. Explicit init avoids it:
from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings
vectordb = Chroma(persist_directory="./db", embedding_function=OpenAIEmbeddings())
retriever = vectordb.as_retriever(search_kwargs={"k": 3})
Dimension mismatch between embeddings and store raises ValueError: shape mismatch. If you switch from text-embedding-ada-002 to a local model, rebuild the index. There is no in-place migration.
With hosted stores like Pinecone, IndexNotFoundError means the index name is wrong or region mismatched. A Document missing page_content raises ValueError during upsert—validate your loaders before they hit the store.
7. Async and event loop pitfalls
Mix sync and async and you meet RuntimeError: Event loop is closed. LangChain’s ainvoke must run inside a live loop:
import asyncio
from langchain.chains import LLMChain
async def run(chain, q):
return await chain.ainvoke({"query": q})
asyncio.run(run(chain, "hi")) # correct
In Jupyter, the loop already exists; in a script it doesn’t. Don’t call asyncio.get_event_loop() blindly—use asyncio.run. If you are already inside a running loop (FastAPI, asyncio server), calling asyncio.run raises RuntimeError: cannot be called from a running event loop. Use await directly.
Tradeoff: sync invoke is simpler but blocks the worker. For Flask/Django, wrap async in a thread or use the sync API. asyncio.TimeoutError from a chain usually means a slow provider, not a code bug—set per-call timeouts.
8. Debugging strategy: verbose, tracing, isolation
When the above don’t explain it, turn on LangChain’s debug flag:
import langchain
langchain.debug = True
This prints every prompt, response, and intermediate step. Beware: it logs full payloads, including keys if you embed them. For production, use LangSmith or OpenLLMetry instead of debug=True.
Ordered path when a new error appears:
- Reproduce with a direct
ChatOpenAI().invoke()call—bypass chains. - If that fails, it’s auth/model/rate limit (sections 1–3).
- If direct call works, add
langchain.debugand inspect the prompt sent by the chain. - If prompt is wrong, fix template (section 4).
- If response is wrong shape, fix parser (section 5).
- If retriever returns nothing, check vector store (section 6).
- If stack mentions
awaitorloop, fix async boundary (section 7).
This sequence cuts debug time from hours to minutes. The common langchain error messages are rarely mysterious once you isolate the layer. Write a tiny script that exercises each component alone; the monolith chain is the last place you should look.