langchain-ai/langchain
Debugging
Tools and techniques for chasing down problems in langchain-ai/langchain code.
Trace everything with LangSmith
The fastest way to see what's happening inside a Runnable, chain, or agent is to enable LangSmith tracing:
export LANGSMITH_TRACING=true
export LANGSMITH_API_KEY=...
export LANGSMITH_PROJECT=my-debuggingEvery Runnable.invoke then produces a tree of runs in LangSmith showing inputs, outputs, timing, and errors at every nested step. This is the most useful single tool for debugging anything model-related.
Trace locally with ConsoleCallbackHandler
If you don't want LangSmith, you can render the same run tree to stdout:
from langchain_core.tracers.stdout import ConsoleCallbackHandler
chain.invoke(
{"input": "..."},
config={"callbacks": [ConsoleCallbackHandler()]},
)You'll see colorized inputs, outputs, and timings for every nested call.
astream_events for streaming UIs
When debugging a streaming chain or agent, astream_events(input, version="v2") yields a typed event for every nested runnable:
async for event in chain.astream_events({"input": "..."}, version="v2"):
print(event["event"], event.get("name"), event.get("data"))This is what UIs use to show fine-grained progress; it's also great for understanding why a particular tool is or isn't being called.
set_debug(True) for global verbose
from langchain_core.globals import set_debug
set_debug(True)Registers a debug tracer that prints every event to stdout from every Runnable in the process. Loud, but useful for one-off scripts.
Common errors
| Symptom | Likely cause |
|---|---|
OutputParserException: Could not parse... |
Model returned text that doesn't match the parser. Wrap the parser with OutputFixingParser (in langchain-classic) or switch to with_structured_output. |
ToolException: ... |
A tool raised it intentionally. The agent will pass the message back to the model. |
ValidationError: ... Field required (Pydantic) |
A tool's args schema requires a field the model didn't provide. Make the field optional or improve the description. |
ImportError: cannot import name 'ChatXxx' from 'langchain_xxx' |
Partner package not installed: pip install langchain-<provider>. |
RuntimeError: There was a problem encountered with the LLM call (legacy chains) |
Look at LLMChain.callbacks or enable tracing — the underlying error is wrapped. |
KeyError: 'messages' inside an agent |
You passed {"input": "..."} instead of {"messages": [{"role": "user", "content": "..."}]}. |
RecursionError from Runnable |
Set RunnableConfig.recursion_limit higher, or check for a Runnable that calls itself unconditionally. |
| Streaming hangs forever | Check StreamChunkTimeoutError from libs/partners/openai/langchain_openai/chat_models/_client_utils.py — the partner's stream-buffer timeout has a default; set timeout= higher. |
Debugging models
To see exactly what's being sent to a provider's API, set temperature=0 and trace via LangSmith. The inputs field of the model run shows the serialized message list and tool definitions. The extra / outputs fields show usage metadata, finish reason, and raw response.
For partner packages that wrap an SDK, you can also enable the SDK's debug mode (e.g. OPENAI_LOG=debug for openai). The HTTP transcript will appear on stderr.
Debugging tools
For a tool that's misbehaving:
- Call it directly:
tool.invoke({"arg": "..."})— bypass the model. - Inspect its schema:
tool.args_schema.model_json_schema(). - Check whether
@toolcorrectly inferred the schema from your function signature; if not, passargs_schema=explicitly.
Debugging agents
If create_agent doesn't behave as expected:
- Check the agent's compiled graph:
agent.get_graph().draw_ascii()shows the node layout. - Trace via LangSmith — every middleware and tool call appears as a separate run.
- Add a custom middleware that prints the request/response at each hook to see exactly when state changes.
- Use
agent.invoke(input, debug=True)(where supported) for verboselanggraphoutput.
Debugging tests
- Run a single test:
uv run --group test pytest path/to/test.py::TestClass::test_method -v. - Drop into pdb on failure:
uv run --group test pytest --pdb. - Check what
pytest-socketblocked: failures will tell you the address attempted; mock or move to integration tests. - Update a snapshot test:
uv run --group test pytest --snapshot-update path/to/test.py. - Re-record VCR cassettes: set
VCR_RECORD_MODE=new_episodesand run with the relevant API key.
See also
- How to contribute / testing — testing infrastructure
- Primitives / callbacks-and-tracers — the observability backbone
- Reference / configuration — environment variables and toggles
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.