Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

langchain — Admin Guide

Generated September 2026 from langchain-ai/langchain at a9780cd

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

This guide is for architects, platform engineers, security reviewers and contributors who run LangChain-based agents in production or work on the framework itself. It documents how the langchain-ai/langchain Python monorepo (commit a9780cd) is built, every configuration surface, the security model, operations, performance levers, the extension contracts, and the internals of the agent runtime. The companion User Guide covers task-oriented usage.


1. Executive Summary

Aspect Summary
What it is A Python framework (MIT licensed, © LangChain, Inc.) for building LLM agents and applications. It is an importable library — no server, daemon, database or config file of its own.
Shape of the repo A uv monorepo of independently versioned packages under libs/: core (langchain-core 1.6.6), langchain_v1 (langchain 1.4.3), langchain (langchain-classic 1.0.8, legacy), text-splitters (1.1.2), standard-tests (langchain-tests 1.1.9), model-profiles (0.0.6) and 16 provider packages under partners/. There is no root pyproject.toml.
Built with Python ≥ 3.10, Pydantic v2, LangGraph 1.2.x (agent runtime), LangSmith SDK (tracing), httpx, tenacity; hatchling builds; uv, ruff, mypy/ty, pytest for development.
Core abstraction The Runnable protocol (invoke/stream/batch + async) implemented by every model, prompt, parser, tool and retriever, composable with `
Agent runtime create_agent compiles a LangGraph StateGraph with a model node, a tool node and one node per middleware hook; wrap_model_call/wrap_tool_call middleware nest around execution.
Deployment shape Embedded in your application process. Durable state (conversation memory, interrupts) lives in a LangGraph checkpointer you supply; vector data lives in the vector store you choose.
Operational burden Low for the library itself; the real work is provider credentials, rate limits, persistence back ends, tracing/observability, and securing tool execution (shell, filesystem, HTTP, deserialization).
Security posture Defense-in-depth features exist (SSRF-safe HTTP client, sandboxed jinja2, deserialization allowlists, path-traversal checks, Docker/Codex shell policies, HITL approval, PII middleware), but LangChain executes whatever tools you give it. The repository ships no SECURITY.md.

Important

Treat an agent as untrusted code execution driven by model output. Every tool is a capability you grant the model; the framework does not sandbox tools unless you use a sandboxing middleware or policy.


2. Architecture

2.1 Layered view

┌───────────────────────────────────────────────────────────────────────────────┐
│ Application code                                                              │
├───────────────────────────────────────────────────────────────────────────────┤
│ langchain (libs/langchain_v1)                                                 │
│   agents/factory.py ── create_agent → LangGraph StateGraph                    │
│   agents/middleware/ ── 16 built-in middleware + hook types + decorators      │
│   agents/structured_output.py ── ToolStrategy / ProviderStrategy / Auto       │
│   chat_models/base.py ── init_chat_model + _ConfigurableModel                 │
│   embeddings/base.py ── init_embeddings                                       │
│   mcp/ ── MCPAdapter (FastMCP) + elicitation-as-interrupt (beta)              │
├───────────────────────────────────────────────────────────────────────────────┤
│ langgraph 1.2.x ── StateGraph, ToolNode, checkpointers, stores, interrupts    │
├───────────────────────────────────────────────────────────────────────────────┤
│ langchain-core (libs/core)                                                    │
│   runnables/ · language_models/ · messages/ · tools/ · prompts/               │
│   output_parsers/ · callbacks/ · tracers/ · load/ · vectorstores/ · indexing/ │
│   _security/ (SSRF policy + transports, internal)                             │
├───────────────────────────────────────────────────────────────────────────────┤
│ Provider packages (libs/partners/*) ── subclass BaseChatModel, Embeddings,    │
│   VectorStore, BaseTool; ship model profiles and provider middleware          │
└───────────────────────────────────────────────────────────────────────────────┘
       ▲ standard-tests (conformance suites)   ▲ model-profiles (profile generator CLI)

2.2 Component inventory

Component Location Responsibility
create_agent libs/langchain_v1/langchain/agents/factory.py (2,164 lines) Resolves model/tools/response format, validates middleware, builds nodes and conditional edges, compiles the graph with recursion_limit=9_999 and metadata ls_integration="langchain_create_agent"
Middleware types agents/middleware/types.py (2,201 lines) AgentMiddleware, AgentState, ModelRequest, ModelResponse, ExtendedModelResponse, OmitFromSchema, decorators, hook_config
Built-in middleware agents/middleware/*.py Retry, fallback, limits, HITL, PII, summarization, context editing, todos, tool selection, provider tool search, tool emulation, tool errors, shell, file search
Structured output agents/structured_output.py Schema specs, strategy classes, parsing bindings, error types
Subagent streaming agents/_subagent_transformer.py Promotes nested named agents to typed handles on run.subagents
init_chat_model chat_models/base.py 30-entry provider registry, name-based inference, configurable model proxy
init_embeddings embeddings/base.py 10-entry provider registry
MCP adapter mcp/adapter.py, mcp/tools.py, mcp/elicitation.py FastMCP client wrapping, MCP→LangChain tool conversion, elicitation loop
Runnable protocol libs/core/langchain_core/runnables/ (14,312 lines) Composition, config propagation, batching, retries, fallbacks, configurable fields, event streaming
Chat model base language_models/chat_models.py Invoke/stream plumbing, caching, rate limiting, streaming fallback, v3 event protocol, profiles
Messages messages/ (9,479 lines) Message classes, standard content blocks, provider block translators, utilities
Tools tools/ BaseTool, StructuredTool, @tool, injected args, retriever tool
Serialization load/ dumpd/dumps/load/loads with allowlists, secret handling, injection escaping
Callbacks & tracers callbacks/, tracers/ Handler hooks, managers, LangSmith tracer, event-stream tracer
SSRF protection _security/ Policy, URL/IP validation, pinned-IP httpx transports (internal API)

2.3 Data Layer

LangChain owns no database. Data flows through four stores that you choose:

Data Where it lives Owned by
Conversation state (messages, structured_response, middleware fields such as todos, thread_model_call_count) LangGraph checkpointer passed to create_agent(checkpointer=...), keyed by configurable.thread_id LangGraph
Cross-thread memory LangGraph store (create_agent(store=...)), reachable in tools via ToolRuntime.store LangGraph
Embeddings + documents A VectorStore implementation (InMemoryVectorStore, Chroma, QdrantVectorStore, …) Provider package / your database
Indexing bookkeeping A RecordManager (InMemoryRecordManager in core; SQLRecordManager in langchain-classic) Your database

Agent state schema (AgentState): messages (reducer add_messages), jump_to (ephemeral, private), structured_response (omitted from input). Middleware state_schemas are merged in registration order with the caller's state_schema last, so the caller wins field conflicts. Fields annotated PrivateStateAttr are hidden from both the input and output schemas; OmitFromInput/OmitFromOutput hide one side. Middleware counters that must not persist across runs (run_model_call_count, run_tool_call_count, shell session resources) are annotated UntrackedValue.

2.4 Caching

Cache Scope Configuration Notes
LLM response cache Process or back end you supply set_llm_cache(BaseCache) globally, or cache= per model Lookup keys strip message IDs; cache hits bypass the rate limiter; not used for streaming. InMemoryCache(maxsize=None) evicts FIFO, no TTL
LangGraph node cache Graph create_agent(cache=BaseCache) (LangGraph's cache) Passed straight to graph.compile
Provider prompt caching Provider side AnthropicPromptCachingMiddleware(ttl="5m"|"1h"), FireworksPromptCachingMiddleware, OpenAI prompt_cache_options field Anthropic marks the last system block and last tool with cache_control; Fireworks pins session affinity to SHA-256(thread_id)
Model-provider registry Process functools.lru_cache on _get_chat_model_creator / _get_embeddings_class_creator Avoids repeated imports
Schema type hints Process lru_cache(maxsize=100) in factory._get_schema_type_hints Speeds repeated create_agent calls
Tool call schema Per tool instance memoized tool_call_schema Invalidated when name, description or args_schema is reassigned

2.5 How the pieces connect at runtime

agent.invoke({"messages": [...]}, config, context=ctx)
  │
  ├─ LangGraph Pregel loop (checkpoint load if thread_id + checkpointer)
  │
  ├─ node "<Mw>.before_agent"  (once)          ── returns state update / jump_to
  ├─ node "<Mw>.before_model"  (each turn)
  ├─ node "model"
  │     ModelRequest(model, messages, system_message, tools, response_format, state, runtime)
  │     └─ wrap_model_call chain: Mw1(Mw2(...(_execute_model)))
  │           _get_bound_model → bind_tools(... tool_choice, strict) or bind(**model_settings)
  │           model.invoke([system_message, *messages])
  │           _handle_model_output → structured_response / retry ToolMessages
  │     → list[Command(update=...)] (+ middleware commands)
  ├─ node "<Mw>.after_model"   (reverse order)
  ├─ edge model→tools: Send("tools", [tool_call]) per pending call (parallel)
  ├─ node "tools" (ToolNode) ── wrap_tool_call chain → tool.invoke → ToolMessage | Command
  ├─ edge tools→model | exit (return_direct / structured output)
  └─ node "<Mw>.after_agent"   (once) → END (checkpoint saved)

3. System Requirements

Item Requirement
Python >=3.10.0,<4.0.0 for every package. CI covers 3.10–3.14 for langchain-core, 3.10 and 3.14 for other packages; releases build on 3.11
Operating systems Any CPython platform. HostExecutionPolicy CPU/memory limits need the POSIX resource module (Linux uses prlimit after spawn; macOS uses preexec_fn); on Windows those limits raise RuntimeError. OpenAI TCP keepalive tuning sets only SO_KEEPALIVE on Windows
Memory / CPU Library overhead is small; size for your checkpointer, vector store and any local models (Hugging Face pipelines, Ollama)
Network Outbound HTTPS to model providers; optional LangSmith (api.smith.langchain.com via the SDK) and gateway (https://gateway.smith.langchain.com); https://models.dev/api.json only for the profile CLI
Key dependency ranges pydantic>=2.7.4,<3, langgraph>=1.2.11,<1.3.0 (for langchain), langsmith>=0.3.45,<1 (core), openai>=2.45.0,<4 (langchain-openai), anthropic>=0.120.0,<2 (langchain-anthropic), fastmcp>=4.0.1,<5 (MCP extra)
Optional tools docker CLI (DockerExecutionPolicy), codex CLI (CodexSandboxExecutionPolicy), rg ripgrep (FilesystemFileSearchMiddleware, falls back to Python), numpy (InMemoryVectorStore, simsimd used if present), transformers (default GPT-2 token counting), grandalf/pygraphviz/pyppeteer (graph drawing)
Development uv (CI pins 0.12.8), make, Docker (for libs/langchain_v1 tests that start Postgres/Redis via compose)

4. Configuration Mastery

There is no global config file. The configuration surfaces are, in order of precedence for a single call: per-call config → constructor arguments → environment variables → library defaults.

4.1 Framework environment variables

Variable Read by Default Effect
LC_OUTPUT_VERSION BaseChatModel.output_version, ChatOpenAI.output_version unset (None) v0 provider-native content; v1 standard content blocks. OpenAI also accepts responses/v1
LANGSMITH_TRACING / LANGCHAIN_TRACING_V2 langsmith SDK (core delegates to langsmith.utils.tracing_is_enabled()) off Enables LangChainTracer on every run
LANGSMITH_API_KEY, LANGSMITH_PROJECT, LANGSMITH_ENDPOINT langsmith SDK — Tracing credentials, project and endpoint
LANGCHAIN_TRACING, LANGCHAIN_HANDLER callbacks/manager.py — Setting either raises RuntimeError (tracer v1 removed)
LANGSMITH_GATEWAY langchain_core/utils/_gateway.py disabled true/1/yes → https://gateway.smith.langchain.com/{provider_path}; false/0/no/unset → off; any other value → custom gateway base URL. Honored by ChatOpenAI, ChatAnthropic, ChatFireworks only
LANGSMITH_GATEWAY_API_KEY _gateway.py — Gateway key (only when the gateway is enabled)
LANGCHAIN_ENV _security/_policy.py, _security/_ssrf_protection.py — Values starting local allow localhost/testserver through the SSRF policy; local_test also bypasses legacy checks for test*server* hosts
LANGCHAIN_OPENAI_STREAM_CHUNK_TIMEOUT_S ChatOpenAI.stream_chunk_timeout 120.0 Max gap between parsed chunks on async streams before StreamChunkTimeoutError
LANGCHAIN_OPENAI_TCP_KEEPALIVE langchain_openai transport 1 0 disables socket keepalive tuning
LANGCHAIN_OPENAI_TCP_KEEPIDLE / _KEEPINTVL / _KEEPCNT / _USER_TIMEOUT_MS langchain_openai transport 60 / 10 / 3 / 120000 Linux-style TCP keepalive tuning; invalid values fall back with a warning
HTTP_PROXY, HTTPS_PROXY, ALL_PROXY (any case) langchain_openai transport — Detected to alter transport injection
LANGCHAIN_CODEX_ORIGINATOR _ChatOpenAICodex (experimental, private) langchain originator header
GITHUB_ACTIONS, LANGSMITH_TAGS, LANGSMITH_METADATA langchain_tests._langsmith_plugin — CI-only trace tagging

Caution

Gateway key precedence: when LANGSMITH_GATEWAY is set to a custom URL and LANGSMITH_GATEWAY_API_KEY is absent, LANGSMITH_API_KEY is used as the provider credential and sent to that URL. Only point LANGSMITH_GATEWAY at hosts you trust with that key.

4.2 Provider credential and endpoint variables

Package / class Variable Notes
ChatOpenAI OPENAI_API_KEY, OPENAI_API_BASE, OPENAI_BASE_URL (SDK), OPENAI_ORG_ID → OPENAI_ORGANIZATION, OPENAI_PROXY Base URL precedence: base_url kwarg → OPENAI_API_BASE → gateway → SDK (OPENAI_BASE_URL)
OpenAIEmbeddings / OpenAI OPENAI_API_KEY, OPENAI_API_BASE, OPENAI_ORG_ID/OPENAI_ORGANIZATION, OPENAI_PROXY, OPENAI_API_VERSION, OPENAI_API_TYPE
AzureChatOpenAI AZURE_OPENAI_ENDPOINT, AZURE_OPENAI_API_KEY → OPENAI_API_KEY, OPENAI_API_VERSION (no default), AZURE_OPENAI_AD_TOKEN, OPENAI_API_TYPE (default azure) Workload identity when AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_FEDERATED_TOKEN_FILE are all set and azure-identity is installed
AzureOpenAIEmbeddings same as chat; OPENAI_API_VERSION defaults to 2023-05-15
ChatAnthropic ANTHROPIC_API_KEY, ANTHROPIC_API_URL → ANTHROPIC_BASE_URL, ANTHROPIC_PROXY Default URL https://api.anthropic.com
ChatFireworks & co. FIREWORKS_API_KEY, FIREWORKS_API_BASE
ChatGroq GROQ_API_KEY, GROQ_API_BASE, GROQ_PROXY
ChatMistralAI MISTRAL_API_KEY, MISTRAL_BASE_URL Embeddings ignore MISTRAL_BASE_URL; tokenizer download may need HF_TOKEN
ChatXAI XAI_API_KEY, XAI_API_BASE (default https://api.x.ai/v1/)
ChatDeepSeek DEEPSEEK_API_KEY, DEEPSEEK_API_BASE (default https://api.deepseek.com/v1) strict=True switches to https://api.deepseek.com/beta
ChatOpenRouter OPENROUTER_API_KEY, OPENROUTER_API_BASE, OPENROUTER_APP_URL (default https://docs.langchain.com), OPENROUTER_APP_TITLE (default LangChain), OPENROUTER_SESSION_ID App URL/title sent as HTTP-Referer / X-Title
ChatPerplexity PPLX_API_KEY only Embeddings/retriever/tool also accept PERPLEXITY_API_KEY
Hugging Face HUGGINGFACEHUB_API_TOKEN → HF_TOKEN, HF_INFERENCE_ENDPOINT Token only sent to huggingface.co / hf.space hosts
NomicEmbeddings NOMIC_API_KEY Triggers nomic.login()
Exa EXA_API_KEY
Legacy Qdrant QDRANT_API_KEY QdrantVectorStore does not read it
TypeSafeClassifier TYPESAFE_API_KEY, TYPESAFE_BASE_URL (default https://api.typesafe.ai)
ChatOllama, Chroma none Pass base_url / connection args explicitly

4.3 RunnableConfig (per call)

Key Type Default Behavior
tags list[str] [] Merged across nested calls (union, sorted)
metadata dict {} Merged; configurable["model"] and checkpoint_ns strings are copied into metadata
callbacks handlers or manager None Inherited by child runs
run_name str class name Trace name
max_concurrency int | None executor default Only the first config's value is used in batch
recursion_limit int 25 Only enforced for RunnableLambda returning runnables; agents set 9,999
configurable dict {} Runtime params (thread_id, configurable fields). Unknown top-level keys are moved here silently
run_id UUID generated For batch, only element 0 keeps it (with a RuntimeWarning)

Warning

Scalar configurable values (str/int/float/bool, not starting with __) are copied into LangSmith trace metadata. Only api_key is excluded. Never pass secrets through configurable when tracing is on.

4.4 BaseChatModel / BaseLanguageModel fields (all chat models)

Field Default Meaning
cache None True global cache, False none, None global if set, or a BaseCache
verbose get_verbose() Adds StdOutCallbackHandler
callbacks, tags, metadata None Attached to every call
custom_get_token_ids None Custom tokenizer for get_num_tokens
rate_limiter None BaseRateLimiter; acquire(blocking=True) before each non-cached call
disable_streaming False True always invoke; "tool_calling" disable only when tools are bound
output_version LC_OUTPUT_VERSION or None Content representation
profile provider-resolved or None ModelProfile capability dict (beta)

Every model's metadata also gets lc_versions (package versions) at construction.

4.5 Key provider constructor fields

ChatOpenAI

Field (alias) Default Notes
model_name (model) "gpt-3.5-turbo" Set explicitly — the default is legacy
openai_api_key (api_key) env SecretStr or sync/async callable
openai_api_base (base_url) None
request_timeout (timeout) None
max_retries None (SDK default)
max_tokens (max_completion_tokens) None
stream_usage auto Auto-enabled only for the default OpenAI endpoint with no proxy or custom client
reasoning_effort, reasoning, verbosity None Reasoning controls
use_responses_api None (auto) Auto when built-in tools, reasoning, include, truncation, context_management, previous_response_id, use_previous_response_id, output_version="responses/v1", or models gpt-5-pro, gpt-5.2-pro, gpt-5.4-pro, gpt-5.5-pro, gpt-5.6-sol, *codex*
service_tier None auto/default/flex
store, truncation, include, context_management, prompt_cache_options None Responses API options
stream_chunk_timeout env or 120.0 Async streams only
include_response_headers False
disabled_params None Strip unsupported params
http_client, http_async_client, http_socket_options, default_headers, default_query, extra_body None Transport customization

AzureChatOpenAI adds azure_endpoint, deployment_name (azure_deployment), openai_api_version (api_version), azure_ad_token, azure_ad_token_provider, azure_ad_async_token_provider, model_version, validate_base_url=True; model_name is for tracing/token counting only and does not select the deployment.

ChatAnthropic

Field (alias) Default Notes
model (model_name) required
max_tokens (max_tokens_to_sample) profile max_output_tokens, else 4096
max_retries 2
default_request_timeout (timeout) None
stream_usage True
thinking None {"type": "enabled", "budget_tokens": N} or {"type": "adaptive"} depending on model
reasoning_effort (effort) None Sets output_config.effort; defaults thinking to adaptive+summarized
output_config, betas, mcp_servers, context_management, container, inference_geo, user_profile_id None Advanced API features; tool types auto-add required beta headers

ChatOllama: model required; base_url=None (SDK default; supports http://user:pass@host converted to auth headers); reasoning; validate_model_on_init=False; num_ctx, num_predict, temperature, top_k, top_p, seed, format, keep_alive, client_kwargs/sync_client_kwargs/async_client_kwargs.

Defaults that differ by provider:

Class Default model Default temperature Default retries
ChatOpenAI gpt-3.5-turbo None SDK
ChatAnthropic required None 2
ChatGroq required 0.7 2
ChatMistralAI mistral-small 0.7 5 (timeout 120 s)
ChatXAI grok-4 None inherited
ChatPerplexity sonar 0.7 6
ChatDeepSeek, ChatFireworks, ChatOpenRouter, ChatOllama required — Fireworks/OpenRouter 2

4.6 init_chat_model configuration

Parameter Default Behavior
model None "provider:model" or bare name; None makes a configurable model
model_provider None Explicit provider (normalized: -→_, lowercase)
configurable_fields None, or ("model", "model_provider") when model is None "any" or a list/tuple of field names
config_prefix "" Namespaces runtime keys as {prefix}_{field}
**kwargs — Passed to the provider class constructor

The configurable model queues bind_tools and with_structured_output calls and replays them on the concrete model built per call. Batch calls with more than one config fall back to the generic executor so each input may use a different model.

4.7 Middleware configuration reference

Middleware Constructor Validation / notes
ModelRetryMiddleware (*, max_retries=2, retry_on=default_retry_on, on_failure="continue", backoff_factor=2.0, initial_delay=1.0, max_delay=60.0, jitter=True) default_retry_on: ModelError.is_retryable for core ModelErrors, True for any other exception. Rejects negative values
ToolRetryMiddleware same + tools=None on_failure legacy values raise/return_message warn
ModelFallbackMiddleware (first_model, *additional_models) Strings resolved with init_chat_model
ModelCallLimitMiddleware (*, thread_limit=None, run_limit=None, exit_behavior="end") One limit required; exit_behavior ∈ {end, error}
ToolCallLimitMiddleware (*, tool_name=None, thread_limit=None, run_limit=None, exit_behavior="continue") run_limit ≤ thread_limit; exit_behavior ∈ {continue, error, end}
ToolErrorMiddleware (on_error=None, *, aon_error=None, tools=None) At least one handler
HumanInTheLoopMiddleware (interrupt_on, *, description_prefix="Tool execution requires approval", edit_notice=<default>) Entries: True (all four decisions), False (auto-approve) or InterruptOnConfig(allowed_decisions, description, args_schema, when)
PIIMiddleware (pii_type, *, strategy="redact", detector=None, apply_to_input=True, apply_to_output=False, apply_to_tool_results=False) Name is PIIMiddleware[<type>]; streaming redaction lookback 128 chars
SummarizationMiddleware (model, *, trigger=None, keep=("messages", 20), token_counter=count_tokens_approximately, summary_prompt=DEFAULT_SUMMARY_PROMPT, trim_tokens_to_summarize=4000) No trigger → never runs; fraction needs a profile; summary calls retried up to 3 attempts
ContextEditingMiddleware (*, edits=None, token_count_method="approximate", token_counter=None) Default edit ClearToolUsesEdit(trigger=100000, clear_at_least=0, keep=3, clear_tool_inputs=False, exclude_tools=(), placeholder="[cleared]")
TodoListMiddleware (*, system_prompt=..., tool_description=...) Adds write_todos, state key todos
LLMToolSelectorMiddleware (*, model=None, system_prompt=..., max_tools=None, always_include=None, max_retries=1, on_parsing_failure="error") on_parsing_failure ∈ error/none/all/list/callable
ProviderToolSearchMiddleware (*, searchable_tools=None) Anthropic tool_search_tool_bm25_20251119, OpenAI tool_search
LLMToolEmulator (*, tools=None, model=None) Implicit default model deprecated
ShellToolMiddleware (workspace_root=None, *, startup_commands=None, shutdown_commands=None, execution_policy=None, redaction_rules=None, tool_description=None, tool_name="shell", shell_command=None, env=None) Temp workspace when workspace_root omitted; env omitted → inherits process env
FilesystemFileSearchMiddleware (*, root_path, use_ripgrep=True, max_file_size_mb=10) Rejects .. and ~

Execution policy fields:

Policy Fields (defaults)
all (BaseExecutionPolicy) command_timeout=30.0, startup_timeout=30.0, termination_timeout=10.0, max_output_lines=100, max_output_bytes=None
HostExecutionPolicy cpu_time_seconds=None, memory_bytes=None, create_process_group=True
CodexSandboxExecutionPolicy binary="codex", platform="auto" (macos/linux), config_overrides={}
DockerExecutionPolicy binary="docker", image="python:3.12-alpine3.19", remove_container_on_exit=True, network_enabled=False, extra_run_args=None, memory_bytes=None, cpus=None, read_only_rootfs=False, user=None (cpu_time_seconds rejected)

Process-wide middleware tracing default: configure_trace_policy(TracePolicy | None) — read at span creation, so it applies to agents built before or after the call. A middleware's own trace_policy attribute overrides it wholesale.

4.8 Serialization (load/loads) parameters

Parameter Default Guidance
allowed_objects None → behaves as "core" with a pending-deprecation warning Use "messages" or an explicit class list for untrusted data
secrets_map None Supply secrets explicitly
secrets_from_env False Keep False: a payload can name any environment variable
valid_namespaces None Adds to the default trusted namespaces
additional_import_mappings None Extends/overrides class mappings
ignore_unserializable_fields False
init_validator default_init_validator Blocks template_format="jinja2" before instantiation

5. Deployment

LangChain is deployed inside your application. The deployment decisions are about process model, persistence and isolation.

5.1 Deployment patterns

Pattern How Considerations
Library in a web service Build agents once at startup (create_agent is relatively expensive), call ainvoke/astream per request Use async paths under ASGI servers; MCP tools are async-only
Stateful assistant Supply a persistent LangGraph checkpointer; map each conversation to a thread_id InMemorySaver is per-process and non-durable
Human-approval workflows HumanInTheLoopMiddleware + checkpointer; persist the thread_id and resume with Command(resume=...) from any worker Every resume must reach the same checkpointer
Batch / offline jobs batch/abatch with max_concurrency, InMemoryRateLimiter Rate limiter is per-process only
LangGraph platforms create_agent returns a compiled graph; the repo's MCP examples include a langgraph.json graph-factory pattern (examples/mcp/graph_factory.py) One long-lived MCPAdapter shared by every run
  • [ ] Pin exact versions of langchain, langchain-core, langgraph and each provider package
  • [ ] Choose and configure a durable checkpointer
  • [ ] Put provider keys in a secret manager and inject as environment variables
  • [ ] Decide tracing (LANGSMITH_TRACING) and payload policy (TracePolicy)
  • [ ] Add ModelCallLimitMiddleware/ToolCallLimitMiddleware to every production agent
  • [ ] Gate destructive tools with HumanInTheLoopMiddleware
  • [ ] Isolate shell/code tools with DockerExecutionPolicy or an external sandbox

5.2 Docker

The repository uses Docker in two places.

Development container (.devcontainer/): devcontainer.json names the container langchain, uses a Compose service built from libs/langchain/dev.Dockerfile (FROM python:3.14-slim-bookworm, installs uv, runs uv sync --dev, user vscode uid 1000), mounts the workspace at /workspaces/langchain on volume langchain-workspaces, sets UV_LINK_MODE=copy, adds the git and github-cli features, and runs cd libs/langchain_v1 && uv sync after creation.

# VS Code: "Dev Containers: Reopen in Container", or with the CLI:
devcontainer up --workspace-folder .

Shell-tool isolation (DockerExecutionPolicy): ShellToolMiddleware can run the agent's shell in a dedicated container per run, with --network none by default, optional read-only root filesystem, user remapping, memory and CPU limits. The workspace is bind-mounted only when it is an existing non-temporary directory.

from langchain.agents.middleware import DockerExecutionPolicy, ShellToolMiddleware

policy = DockerExecutionPolicy(
    image="python:3.12-alpine3.19",
    network_enabled=False,
    read_only_rootfs=True,
    user="1000:1000",
    memory_bytes=512 * 1024 * 1024,
    cpus="1.0",
)
shell = ShellToolMiddleware(workspace_root="/srv/agent-workspace", execution_policy=policy)

Warning

Container isolation is only as strong as the Docker daemon configuration. Run agents on hosts with rootless Docker or AppArmor/SELinux, and review anything passed through extra_run_args.

Note

The repository does not ship a Dockerfile or image for running applications — containerize your own application as usual and install the LangChain packages into it.

5.3 Test infrastructure containers

libs/langchain_v1 unit tests start Postgres and Redis for checkpointer tests:

cd libs/langchain_v1
make start_services   # docker compose -f tests/unit_tests/agents/compose-postgres.yml -f .../compose-redis.yml up -V --force-recreate --wait --remove-orphans
make test             # starts services, runs pytest, always stops services
make test_fast        # LANGGRAPH_TEST_FAST=1, no Docker services

6. Security

LangChain's threat surface is the union of (a) model output driving tool calls, (b) untrusted data entering prompts, templates, serialized objects and URLs, and (c) credentials held in process memory and environment. The repository has no SECURITY.md and no documented vulnerability-disclosure process; the bug-report issue template refers reporters to "the security option", which ISSUE_TEMPLATE/config.yml does not define. The contributor rules in AGENTS.md require no eval(), exec() or pickle on user-controlled input and no bare except:.

6.1 Authentication

Surface Mechanism
Model providers API keys from constructor (api_key=) or environment (Section 4.2). Keys are stored as Pydantic SecretStr, and Serializable.lc_secrets replaces them with secret placeholders when serializing ({"lc": 1, "type": "secret", "id": ["OPENAI_API_KEY"]})
Dynamic OpenAI keys ChatOpenAI(api_key=callable) accepts a sync or async callable (token refresh); async callables disable the sync client
Azure API key, AAD token (AZURE_OPENAI_AD_TOKEN), token providers (azure_ad_token_provider), or automatic workload identity (WorkloadIdentityCredential, scope https://cognitiveservices.azure.com/.default) when AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_FEDERATED_TOKEN_FILE are set and the azure-identity extra is installed
LangSmith gateway LANGSMITH_GATEWAY_API_KEY, falling back to LANGSMITH_API_KEY only when the base URL came from the gateway
Hugging Face Token is sent only to huggingface.co, hf.space and their subdomains; custom endpoint_url hosts receive no token
Ollama base_url may embed user:pass@, converted to auth headers (the docstring warns this is insecure outside trusted networks)
MCP servers Delegated to FastMCP: pre-built `fastmcp.Client(url, auth="<bearer>"
ChatGPT OAuth (experimental, private) langchain_openai.chatgpt_oauth stores tokens at ~/.langchain/chatgpt-auth.json with mode 0600 in a 0700 directory

6.2 Authorization & Access Control

LangChain has no user model; authorization is about what the model may do.

Control How it restricts the model
Tool selection Only tools passed to create_agent (or registered by middleware) can execute; unknown tools added by middleware raise ValueError unless a wrap_tool_call handles them
HumanInTheLoopMiddleware Per-tool approval with approve/edit/reject/respond; when predicates gate conditionally; edits to a tool the agent lacks are rejected
ToolCallLimitMiddleware / ModelCallLimitMiddleware Budget caps per run and per thread
LLMToolSelectorMiddleware, ProviderToolSearchMiddleware Reduce the exposed tool set per turn
File tools FilesystemFileSearchMiddleware and the Anthropic filesystem middleware resolve paths under root_path and reject ../~; the state-backed Claude tools enforce allowed_path_prefixes (memory defaults to /memories)
init_chat_model(configurable_fields=...) With "any", callers can change api_key/base_url at runtime — enumerate fields when config is untrusted
ToolErrorMiddleware Opt-in exception surfacing so internal exception text is not leaked to the model unless you choose to
OpenAIModerationMiddleware Checks input/output/tool results with OpenAI moderation; exit_behavior error/end/replace
TypeSafe AutoModeMiddleware (alpha) Classifies risky tool calls (probability ≥ 0.5 blocked)

Warning

GitHub issue #40492 (open) reports that an after_model middleware returning jump_to="tools" can bypass the HITL pending-tool-call gate and re-execute rejected calls in langchain 1.4.0. Avoid jump_to="tools" in custom middleware used alongside HumanInTheLoopMiddleware until resolved.

6.3 TLS / Certificates

  • Provider SDKs (openai, anthropic, groq, …) and httpx handle TLS. langchain-openai depends on certifi>=2024.6.2; you can supply http_client/http_async_client with custom verify= and certificates.
  • The SSRF-safe transports in langchain_core._security pin the TCP connection to the validated IP while preserving the original Host header and TLS SNI, so certificate validation still targets the hostname.
  • ChatOpenAI image-size fetching (for token counting with allow_fetching_images=True) uses the SSRF-safe client with verify=global_ssl_context and follow_redirects=False, a 5-second timeout and a 50 MB cap.
  • Proxies: OPENAI_PROXY/openai_proxy, ANTHROPIC_PROXY, GROQ_PROXY, or standard HTTP(S)_PROXY variables consumed by httpx. Combining openai_proxy with a custom client raises ValueError.

6.4 SSRF protection

langchain_core._security (explicitly internal, not public API) provides:

Element Default
Allowed schemes http, https
Blocked RFC1918 private ranges, loopback, link-local, CGNAT 100.64/10, TEST-NETs, multicast, reserved; IPv6 ULA/link-local/multicast/mapped/NAT64 (embedded IPv4 extracted and checked)
Always blocked Cloud metadata IPs (169.254.169.254, 169.254.170.2, 169.254.170.23, 100.100.100.200, fd00:ec2::254, …) and hostnames (metadata.google.internal, metadata.amazonaws.com, metadata, instance-data)
Localhost names localhost, localhost.localdomain, host.docker.internal
Kubernetes *.svc.cluster.local
Redirects Re-validated on every hop (follow_redirects=True, max_redirects=10 in the client factories)
DNS rebinding All resolved IPs validated, connection pinned to the first

Users in this repo: langchain-openai image fetching and the deprecated HTMLHeaderTextSplitter.split_text_from_url. LANGCHAIN_ENV values starting with local relax the policy for localhost/testserver — never set it in production.

6.5 Secrets handling

  • Keys are SecretStr; serialization emits placeholders, never values.
  • load(..., secrets_from_env=True) lets a payload pull any environment variable — keep the default False and pass secrets_map explicitly.
  • Trace metadata: every configurable scalar except api_key is copied into LangSmith metadata; every traced run records platform.platform(), Python version and package versions.
  • VCR cassettes in langchain-tests filter authorization, x-api-key and api-key headers to PLACEHOLDER; review cassettes for secrets in bodies before committing.
  • Shell sessions inherit the parent environment unless ShellToolMiddleware(env=...) is given — pass a minimal environment so the agent cannot read provider keys.

6.6 Input validation and injection surfaces

Surface Protection in source Residual risk
Deserialization (load/loads) Namespace allowlist, allowed_objects modes, __lc_escaped__ wrapping of user dicts containing lc, jinja2 blocked by init_validator, DISALLOW_LOAD_FROM_PATH Default "core" mode is unsafe for untrusted manifests; "all" can set a chat model's base_url to an attacker host (SSRF) — documented as expected behavior
Prompt templates f-string validator rejects attribute/index access; jinja2 uses SandboxedEnvironment; mustache traverses only dict/list/tuple Jinja2 sandbox is "best-effort"; never accept jinja2 templates from users
load_prompt (deprecated since 1.2.21) Rejects absolute paths and .. unless allow_dangerous_paths=True; template files must be .txt; YAML via safe_load; jinja2 refused; lc:// hub paths refused —
ImagePromptTemplate path loading removed (0.3.15) —
utils.image.encode_image / image_to_data_url Removed for security (raise ValueError) —
XML parsing XMLOutputParser defaults to defusedxml Switching to parser="xml" reintroduces stdlib XML risks
HTML splitting HTMLSectionSplitter lxml parser with no_network, resolve_entities=False, load_dtd=False, XSLT DENY_ALL —
MCP targets String targets must be http(s) URLs — a string can never launch a subprocess (FastMCP would otherwise treat an existing .py/.js path as a stdio command) Local servers via Path/MCPConfig run arbitrary commands by design
Shell tool Execution policies, output limits, redaction rules HostExecutionPolicy offers no filesystem/network sandboxing
Hugging Face HuggingFacePipeline strips trust_remote_code from model kwargs —
Legacy (langchain-classic) Python REPL tools and LLMBashChain removed (raise errors pointing to langchain-experimental); APIChain requires limit_to_domains; SQL chain carries a security note; LLMMathChain deprecated (numexpr) Classic packages proxy to langchain-community utilities with their own risks

6.7 Network exposure

LangChain opens no listening sockets. Outbound connections go to model providers, LangSmith (if tracing), MCP servers you configure, vector databases, models.dev (profile CLI only) and mermaid.ink (only if you render graphs with the API method).

6.8 Hardening checklist

  • [ ] Use allowed_objects="messages" or an explicit class list for any load/loads of data you did not produce
  • [ ] Keep secrets_from_env=False
  • [ ] Never accept jinja2 templates or configurable_fields="any" from untrusted input
  • [ ] Run shell/code tools under DockerExecutionPolicy (network off, read-only rootfs, non-root user) or an external sandbox
  • [ ] Pass a minimal env= to ShellToolMiddleware
  • [ ] Gate write/delete/payment tools with HumanInTheLoopMiddleware
  • [ ] Set TracePolicy(process_inputs=omit_payload) if traces must not contain conversation content
  • [ ] Use key_encoder="blake2b"/sha256 for index() where collision attacks matter
  • [ ] Do not set LANGCHAIN_ENV=local* outside tests
  • [ ] Point LANGSMITH_GATEWAY only at trusted hosts

7. Operations

7.1 Starting, stopping and upgrading

There is nothing to start or stop — agents live in your process. Upgrades are package upgrades:

pip install -U "langchain==1.4.3" "langchain-core==1.6.6" "langchain-openai==1.6.6"
python -m langchain_core.sys_info

Versioning and release facts from the repository:

  • Each package is released independently through the 🚀 Package Release workflow (_release.yml): build → release notes → pre-release checks (unit tests, minimum-version tests, partner integration tests) → TestPyPI → core-compatibility tests against published anthropic and openai partners → dependents (deepagents) for core/langchain releases → PyPI (trusted publishing) → GitHub release and tag.
  • Within a 0.x series, fixes and additive features take patch bumps.
  • Deprecations name since and removal versions; several removals are scheduled for 2.0.0 (astream_log, astream_events(version="v1"), RunnableWithMessageHistory, load_prompt, .text() as a method, classic memory, hub.push/pull, BaseChatModel.dict()).

Tip

Importing langchain_core turns on display of LangChainDeprecationWarning and LangChainBetaWarning. Run your test suite with warnings as errors for those classes before upgrading to catch scheduled removals early.

7.2 Health and capacity

Concern Mechanism
Runaway loops ModelCallLimitMiddleware, ToolCallLimitMiddleware; the graph recursion limit is 9,999
Provider throttling InMemoryRateLimiter (per process, request-count token bucket starting empty), ModelRetryMiddleware with backoff and jitter; core ModelRateLimitError, ModelAPIError, ModelConnectionError, ModelTimeoutError are is_retryable=True
Provider outages ModelFallbackMiddleware, or Runnable.with_fallbacks (fallbacks apply only before the first streamed chunk)
Context overflow Core ContextOverflowError (provider subclasses: OpenAIContextOverflowError, AnthropicContextOverflowError, GroqContextOverflowError); mitigate with SummarizationMiddleware, ContextEditingMiddleware, trim_messages
Stalled streams ChatOpenAI.stream_chunk_timeout (async) raises StreamChunkTimeoutError

7.3 Logging

Tool Configure Output
Debug mode langchain_core.globals.set_debug(True) ConsoleCallbackHandler prints every run start/end with inputs/outputs
Verbose mode set_verbose(True) or verbose=True on a component StdOutCallbackHandler (chains, agents, tools; not tokens)
Agent graph debug create_agent(debug=True) LangGraph prints node executions and state updates
File log with FileCallbackHandler("run.log"): ... Chain/tool events to a file (use as a context manager)
LangSmith tracing LANGSMITH_TRACING=true Full trace tree; middleware hook spans named <Mw>.wrap_model_call etc.; model calls tagged with ls_integration="langchain_create_agent" and lc_agent_name
Payload policy configure_trace_policy(TracePolicy(process_inputs=omit_payload)) or per-middleware trace_policy Keeps spans and timing, drops payloads; messages still appear on the inner model span
Usage accounting get_usage_metadata_callback() / UsageMetadataCallbackHandler Aggregated UsageMetadata per model name
Python logging Standard logging loggers per module (e.g. langchain.agents.middleware.shell_tool) Configure with logging.getLogger("langchain").setLevel(...)

7.4 Backup & Restore

LangChain holds no durable state itself. Back up what your deployment configures:

Asset Backup Restore
Conversation state Back up the checkpointer's database (Postgres/SQLite/Redis per the LangGraph saver you use) Restore the database; resume threads by thread_id
Cross-thread memory Back up the LangGraph store's database Restore database
InMemoryVectorStore store.dump("vectors.json") (JSON via dumpd, parent dirs created) InMemoryVectorStore.load("vectors.json", embeddings) — loads with allowed_objects=[Document]
External vector stores Use the database's own tools (Chroma persist directory, Qdrant snapshots) Database tools
Indexing record manager Back up with the vector store — they must stay in sync Restore both together, or re-run index(..., cleanup="full")
Serialized chains/prompts dumps(obj, pretty=True) loads(text, allowed_objects=[...])

Caution

Changing index()'s key_encoder after data exists produces duplicates. Rebuild the index when switching encoders.


8. Performance Tuning

Lever Setting Effect / caveat
Parallel batching batch(..., config={"max_concurrency": N}) / abatch Thread pool (sync) or semaphore-bounded gather (async); only the first config's max_concurrency counts
Parallel tools Automatic Each pending tool call is dispatched with its own LangGraph Send; the tool node hydrates state from channels instead of copying full state into each Send (removing an O(N²) write pattern)
Streaming stream/astream, stream_mode="messages" Lower time-to-first-token; disable_streaming="tool_calling" forces non-streaming only when tools are bound
Response caching set_llm_cache(...) Skips provider calls for identical prompts; not for streaming
Prompt caching AnthropicPromptCachingMiddleware, FireworksPromptCachingMiddleware, OpenAI prompt_cache_options Cuts input-token cost/latency on repeated prefixes
Fewer tool schemas LLMToolSelectorMiddleware(model="<small model>", max_tools=N) or ProviderToolSearchMiddleware Smaller requests with large tool catalogs
Context size ContextEditingMiddleware, SummarizationMiddleware, trim_messages Keep requests under the window; summarization adds a model call
Token counting token_count_method="approximate" (default) vs "model"; custom token_counter Approximate is faster; exact may call provider APIs
Rate limiting InMemoryRateLimiter(requests_per_second, max_bucket_size) Smooths bursts per process
OpenAI transport LANGCHAIN_OPENAI_TCP_KEEPALIVE*, http_socket_options, stream_chunk_timeout Detects dead connections faster
Agent construction Build agents once and reuse Schema resolution and graph compilation happen in create_agent
Structured output Let AutoStrategy choose provider-native output where supported Avoids an extra tool round-trip

Note

GitHub issue #40826 (open) reports that streaming a large tool call re-parses its arguments in pure Python on every chunk, and #40877 reports RunnableParallel ignoring max_concurrency on ainvoke/astream while honoring it on sync calls. Benchmark streaming of very large tool arguments and async parallel fan-out in your workload.

The repository measures performance with pytest-benchmark and CodSpeed (make benchmark in libs/core runs pytest tests/benchmarks --codspeed; libs/langchain_v1 has tests/benchmarks/test_create_agent.py).


9. Integrations

9.1 Plugin / Extension System

LangChain has three extension contracts.

1. Provider packages (subclass core interfaces).

To add… Subclass Must implement Should implement
Chat model langchain_core.language_models.BaseChatModel _generate, _llm_type _stream/_astream, bind_tools, with_structured_output, _resolve_model_profile, error translation to core ModelError subclasses
Embeddings langchain_core.embeddings.Embeddings embed_documents, embed_query async variants
Vector store langchain_core.vectorstores.VectorStore similarity_search, from_texts add_texts/add_documents, delete, get_by_ids, MMR, async variants
Retriever langchain_core.retrievers.BaseRetriever _get_relevant_documents _aget_relevant_documents
Tool langchain_core.tools.BaseTool (or @tool) _run _arun, args_schema
Document loader langchain_core.document_loaders.BaseLoader lazy_load alazy_load
Cache / store / chat history BaseCache, BaseStore, BaseChatMessageHistory abstract methods async variants

Conformance is verified with langchain-tests (Section 10.6). Model capability data is shipped as langchain_<pkg>/data/_profiles.py, generated by langchain-profiles refresh and refreshed daily in CI by refresh_model_profiles.yml. Provider-specific content formats are translated to standard content blocks by registering a translator with langchain_core.messages.block_translators.register_translator(provider, translate_content, translate_content_chunk); registered translators in core: anthropic, bedrock, bedrock_converse, google_genai, google_vertexai, groq, openai.

To make init_chat_model / init_embeddings infer your provider, it must be added to _BUILTIN_PROVIDERS in libs/langchain_v1/langchain/chat_models/base.py or embeddings/base.py; otherwise users construct your class directly.

2. Agent middleware. Subclass AgentMiddleware[StateT, ContextT, ResponseT] or use the decorators. Contract:

Attribute / hook Contract
name Unique per agent (default class name)
state_schema AgentState subclass merged into the graph state
tools Extra tools registered with the agent
trace_policy Optional TracePolicy for this middleware's spans
transformers Stream transformer factories (e.g. InternalCallTransformer to hide internal model calls from run.messages)
before_agent, before_model, after_model, after_agent (+ async) Return a state update, Command, or None; declare jumps with @hook_config(can_jump_to=[...])
wrap_model_call / awrap_model_call (request, handler) -> ModelResponse | AIMessage | ExtendedModelResponse; ExtendedModelResponse.command supports update only
wrap_tool_call / awrap_tool_call (request, handler) -> ToolMessage | Command

3. Runnables. Any object implementing Runnable.invoke (or a plain function, generator or dict, via coercion) composes with |. RunnableSerializable.configurable_fields(...) and configurable_alternatives(...) expose runtime-switchable parameters.

9.2 LangGraph

create_agent returns a CompiledStateGraph and accepts LangGraph primitives directly: checkpointer, store, cache, interrupt_before/interrupt_after, Command, Send, Runtime, ToolRuntime, InjectedState, InjectedStore. The compiled agent can be embedded as a subgraph node (the name parameter labels it), and SubagentTransformer exposes nested named agents as typed handles on run.subagents when streaming.

9.3 Model Context Protocol

langchain.mcp (beta) wraps FastMCP:

  • MCPAdapter(target) accepts a URL string (http/https only), Path, FastMCP transport, FastMCP/MCPServer instance, MCPConfig/dict, fastmcp.Client or ClientGroup. It clones and "arms" clients without an elicitation handler so elicitation becomes a LangGraph interrupt(); clients with their own handler are left untouched.
  • list_tools(cache_mode="use"|"refresh"|"bypass") honors the client-side response cache (SEP-2549).
  • Tools are async. Tool metadata is grouped under metadata["mcp"]["tool"] (annotations such as destructive_hint, _meta) and metadata["mcp"]["server"]; structured content is attached as MCPToolArtifact(structured_content=...) on the ToolMessage artifact.
  • Only elicitation is answered; sampling, roots and continuation rounds raise NotImplementedError. Interrupt payload type: "mcp_elicitation" with requests of mode form (JSON-schema) or url.

9.4 LangSmith

Tracing, evaluation and the gateway are provided by the langsmith SDK. The repo's CI sends integration-test traces to LangSmith (LANGSMITH_PROJECT defaults to scheduled-testing-py), bridged by the langchain_tests._langsmith_plugin pytest plugin that only activates when GITHUB_ACTIONS=true.


10. Developer Internals

10.1 Repository structure

langchain/
├── AGENTS.md                 contributor & agent guidelines (authoritative dev rules)
├── README.md, LICENSE (MIT), CITATION.cff
├── .github/                  workflows, actions (uv_setup pins uv 0.12.8), scripts/check_diff.py,
│                             ISSUE_TEMPLATE, CODEOWNERS, dependabot.yml, pr-labeler config
├── .devcontainer/            VS Code dev container (compose + libs/langchain/dev.Dockerfile)
├── .pre-commit-config.yaml   per-package format/lint + version-check hooks
├── .mcp.json                 docs-langchain and reference-langchain MCP servers (for coding agents)
├── openwiki/                 auto-generated code wiki (25 pages; refreshed daily; not authoritative)
└── libs/
    ├── Makefile              lock / check-lock across core, text-splitters, langchain, langchain_v1, model-profiles
    ├── core/                 langchain-core
    ├── langchain_v1/         langchain (import package "langchain")
    ├── langchain/            langchain-classic (import package "langchain_classic")
    ├── text-splitters/       langchain-text-splitters
    ├── standard-tests/       langchain-tests
    ├── model-profiles/       langchain-model-profiles (CLI langchain-profiles)
    └── partners/             16 provider packages, each with pyproject.toml, uv.lock, Makefile, tests/

Each package has its own pyproject.toml, uv.lock and Makefile; local development uses editable path installs declared in [tool.uv.sources] so sibling packages resolve to the working tree. Always cd into a package before running commands.

10.2 Agent factory internals

  1. Model resolution. A string model goes through init_chat_model.
  2. Response format. None → no structured output. ToolStrategy/ProviderStrategy/AutoStrategy are kept; raw schemas become AutoStrategy. For AutoStrategy, a ToolStrategy is built up front so structured-output tools exist at graph-build time; the decision to use ProviderStrategy is made per model call in _get_bound_model via _supports_provider_strategy(model, tools):
    • model.profile["structured_output"] truthy → provider strategy, except Gemini models before the 3-series when tools are bound;
    • otherwise the model name is matched against FALLBACK_MODELS_WITH_STRUCTURED_OUTPUT regexes (GPT-4.1, GPT-4o, GPT-5.x, GPT-6 astra/luna/sol, Claude Opus 4.5–4.8, Sonnet 4.5–4.6, Haiku 4.5, Claude fable/mythos 5, Grok-4, grok-build).
  3. Tools. Dict tools are provider built-ins (bound but not executed locally). Callables and BaseTools plus middleware tools go into a LangGraph ToolNode together with the composed wrap_tool_call chain. A ToolNode exists if there are client-side tools or any wrap-tool middleware.
  4. Middleware validation. Duplicate names raise AssertionError. Hook presence is detected by comparing each class's method with the AgentMiddleware base method (sync or async override counts).
  5. Wrap composition. _chain_model_call_handlers composes right-to-left so the first middleware is outermost; Commands from ExtendedModelResponse are accumulated inner-first, cleared on each inner call for retry safety, and converted into additional Commands after the model's own state update. Commands with goto, resume or graph raise NotImplementedError.
  6. Binding. ProviderStrategy → bind_tools(final_tools, **strategy.to_model_kwargs(), **model_settings) plus strict=True for OpenAI-compatible models not using the Responses API. ToolStrategy → bind_tools(..., tool_choice="any") when structured-output tools exist. Otherwise bind_tools(tools, tool_choice=request.tool_choice) or plain bind(**model_settings).
  7. Invalid tool calls. Before each model call, _patch_invalid_tool_calls appends an error ToolMessage for every unanswered invalid_tool_call; the repaired history replaces the state history via RemoveMessage(REMOVE_ALL_MESSAGES).
  8. Structured output handling. Provider strategy parses the final text when there are no tool calls. Tool strategy parses the schema-tool call; multiple schema calls or validation failures follow handle_errors (retry with a ToolMessage, or raise). When response_format is set and no structured response was produced this turn, structured_response is explicitly reset to None to avoid a stale checkpointed value.
  9. Edges. Entry is the first before_agent, else first before_model, else model. Loop entry is the first before_model or model. after_model hooks chain from last to first. Model→tools routing: honor jump_to; no AI message or no tool calls → exit; pending calls → Send("tools", [call]) each; a fresh structured response → exit; otherwise back to the model (synthetic tool messages were injected). Tools→model routing: exit if all executed client tools are return_direct, or a structured-output tool succeeded; otherwise loop.
  10. Compile. graph.compile(checkpointer, store, interrupt_before, interrupt_after, debug, name, cache, transformers=[ToolCallTransformer, SubagentTransformer, *middleware transformers, *user transformers]) de-duplicated by identity, then .with_config({"recursion_limit": 9999, "metadata": {"ls_integration": "langchain_create_agent", "lc_agent_name": name}}).

10.3 Runnable internals

Mechanism Detail
Composition __or__/__ror__ build RunnableSequence (flattening nested sequences, ≥ 2 steps). Coercion order: Runnable → generator function (RunnableGenerator) → callable (RunnableLambda) → dict (RunnableParallel) → TypeError. __or__ never returns NotImplemented
Config propagation ensure_config merges the context-var parent config; child runs get tags like seq:step:N, map:key:K, retry:attempt:N
Retry RunnableRetry on tenacity with reraise=True; batch retries only failed items; streams are not retried
Fallbacks RunnableWithFallbacks raises the first error if all fail; streaming falls back only before the first chunk; __getattr__ forwards Runnable-returning methods (e.g. bind_tools) to primary and fallbacks
Configurables ConfigurableField, ConfigurableFieldSingleOption/MultiOption, alternatives namespaced which==key/field with prefix_keys
Events astream_events v2 uses an event-stream tracer; v3 is implemented by BaseChatModel and LangGraph only
Chat-model streaming fallback If _stream is not overridden, stream() yields one chunk from invoke()

10.4 Message and serialization internals

  • AIMessage.content_blocks resolution: output_version == "v1" content returned as-is → registered provider translator by response_metadata["model_provider"] → best-effort parse, then missing tool calls appended and reasoning from additional_kwargs prepended.
  • Message dict coercion uses a hard-coded allowlist for {"lc": 1, "type": "constructor", ...} shapes and never calls load().
  • Serializable.is_lc_serializable() defaults to False (opt-in). to_json() merges lc_secrets across the MRO.
  • dumps refuses a custom default= and wraps user dicts that contain an lc key as {"__lc_escaped__": ...}; load unwraps them without instantiation.

10.5 Code patterns and conventions

  • Google-style docstrings with Args:/Returns:/Raises:; types in signatures, not docstrings; single-backtick code in docs; American English.
  • Error messages are built in a msg variable before raise; no bare except:.
  • New public parameters are keyword-only; public signatures are treated as stable (“Would this change break someone's code if they used it last week?”).
  • ruff (format + lint, line length 88), mypy --strict with the pydantic plugin in most packages; text-splitters type-checks with ty.
  • Conventional Commit PR titles with a required scope from the allowed list (core, langchain, langchain-classic, model-profiles, standard-tests, text-splitters, docs, each partner, infra, deps, partners); types feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert, release, hotfix. Branches: <github-username>/<scope>/<short-description>.
  • GitHub Actions must be pinned to full commit SHAs.

10.6 Testing Strategy

Layer Location Rules
Unit tests libs/<pkg>/tests/unit_tests/ No network: pytest-socket --disable-socket --allow-unix-socket; parallel with pytest -n auto (xdist) in core, langchain_v1 and text-splitters; blockbuster detects blocking calls in async code
Integration tests tests/integration_tests/ Live APIs; run daily at 13:00 UTC (integration_tests.yml) on Python 3.10 and 3.14 for OpenAI, Anthropic, Fireworks, Groq, Mistral, xAI and external Google/AWS packages
VCR tests langchain-openai Cassettes in tests/cassettes, replayed with --record-mode=none -m vcr in CI (_test_vcr.yml)
Snapshot tests syrupy --snapshot-update in watch targets
Minimum-version tests _test.yml Re-runs unit tests with minimum dependency versions
Pydantic matrix _test_pydantic.yml Every Pydantic 2.x.0 minor within the supported range, Python 3.12
Benchmarks tests/benchmarks, CodSpeed Python 3.13.11 pinned in codspeed.yml
Standard conformance langchain-tests Subclass ChatModelUnitTests/ChatModelIntegrationTests, EmbeddingsUnitTests/EmbeddingsIntegrationTests, ToolsUnitTests/ToolsIntegrationTests, VectorStoreIntegrationTests, RetrieversIntegrationTests, BaseStoreSyncTests/BaseStoreAsyncTests, SyncCacheTestSuite/AsyncCacheTestSuite

A standard chat-model test class looks like:

from langchain_tests.unit_tests import ChatModelUnitTests
from my_pkg import ChatMyProvider


class TestChatMyProvider(ChatModelUnitTests):
    @property
    def chat_model_class(self):
        return ChatMyProvider

    @property
    def chat_model_params(self):
        return {"model": "my-model-1"}

    @property
    def init_from_env_params(self):
        return ({"MY_PROVIDER_API_KEY": "key"}, {}, {"api_key": "key"})

Capability flags you override include has_tool_calling, has_tool_choice, has_structured_output, supports_json_mode, supports_image_inputs, supports_image_urls, supports_pdf_inputs, supports_audio_inputs, supports_video_inputs, supports_image_tool_message, supports_pdf_tool_message, returns_usage_metadata, supported_usage_metadata_details, enable_vcr_tests. test_no_overrides_DO_NOT_OVERRIDE fails if you delete or override a standard test without @pytest.mark.xfail(reason=...).

Per-package Makefile targets:

Package make test runs Other notable targets
libs/core Unsets LANGCHAIN_TRACING_V2, LANGCHAIN_API_KEY, LANGSMITH_API_KEY, LANGSMITH_TRACING, LANGCHAIN_PROJECT, then uv run --group test pytest -n auto --benchmark-disable --disable-socket --allow-unix-socket extended_tests, lint (+ lint_imports.sh), type, format, benchmark, check_imports, check_version
libs/langchain_v1 Starts Postgres/Redis, LANGGRAPH_TEST_FAST=0 … pytest -n auto … --snapshot-update, stops services test_fast, coverage, coverage_agents, integration_tests, benchmark
libs/partners/openai Downloads cl100k_base/o200k_base into tiktoken_cache/, then TIKTOKEN_CACHE_DIR=tiktoken_cache … pytest --disable-socket --allow-unix-socket integration_tests (SDK smoke tests against openai 2.x and 3.x, then full suite), test_vcr
libs/text-splitters pytest -n auto --disable-socket --allow-unix-socket lint uses ty check
libs/standard-tests pytest (no socket flags) integration_tests
libs/model-profiles pytest --disable-socket --allow-unix-socket refresh-profiles for all 10 providers with profiles
libs/ — make lock, make check-lock

CI change detection (.github/scripts/check_diff.py): changes in core → test core and every later package in the order core, text-splitters, langchain, langchain_v1, model-profiles; changes in standard-tests → also test mistralai, openai, anthropic, fireworks, groq; workflow changes → test all; ≥ 300 changed files → everything; an unknown libs/<x> directory fails CI with Unknown lib: … check_diff.py likely needs an update for this new library!.


11. Troubleshooting

Operator-grade entries: deployment, configuration, security controls, serialization, providers, persistence and the development toolchain. Messages are quoted from source; {...} marks runtime values and … marks shortened text. Everyday agent/tool/prompt errors are covered in the User Guide.

Error: Deserialization of {mapping_key!r} is not allowed. The default (allowed_objects='core') only permits core langchain-core classes. To allow trusted partner integrations, use allowed_objects='all'. …

Cause: load/loads met a class (for example ChatOpenAI) outside the active allowlist. Solution: For trusted payloads pass an explicit list: loads(text, allowed_objects=[ChatOpenAI, ChatPromptTemplate]). Use "all" only for payloads you produced. Prevention: Decide the allowlist per data source; never use "all" on user uploads.

Error: Jinja2 templates are not allowed during deserialization for security reasons. Use 'f-string' template format instead, or explicitly allow jinja2 by providing a custom init_validator.

Cause: A serialized prompt uses template_format="jinja2". Solution: Convert the prompt to f-string or mustache and re-serialize; only supply a permissive init_validator for fully trusted data. Prevention: Standardize on f-string templates.

Error: Trying to deserialize something that cannot be deserialized in current version of langchain-core: {mapping_key}.

Cause: The payload references a langchain_community or langchain path that is only loadable through the mapping table, or a class removed in this version. Solution: Re-serialize with current packages, or add a mapping via additional_import_mappings. Prevention: Version serialized artifacts alongside package versions.

Error: Trying to load an object that doesn't implement serialization: {value}

Cause: The object was dumped as {"type": "not_implemented"} because its class is not Serializable (is_lc_serializable() is False by default). Solution: Persist configuration yourself, or make the class opt in with is_lc_serializable() returning True. Prevention: Test loads(dumps(obj)) round-trips in CI.

Error: allowed_objects must contain Serializable subclasses.

Cause: A non-class or non-Serializable entry in allowed_objects. Solution: Pass classes such as AIMessage, not instances or strings (strings are only "all", "core", "messages"). Prevention: —

Error: `default` should not be passed to dumps

Cause: dumps(obj, default=...). Solution: Remove default; dumps supplies its own encoder. Use pretty=True or indent= for formatting. Prevention: —

Error: Class {cls} has a deprecated attribute {attr}. Please use the corresponding classmethod instead.

Cause: A custom Serializable still defines a legacy attribute (such as lc_namespace) instead of the classmethod. Solution: Implement get_lc_namespace() / is_lc_serializable() classmethods. Prevention: Follow the current Serializable API in integrations.

Error: SSRF blocked: {reason} (SSRFBlockedError)

Cause: A URL fetched through the SSRF-safe client resolved to a private, loopback, link-local, cloud-metadata or cluster-internal address, or used a non-http(s) scheme (reasons include localhost address, invalid IP address, scheme '{scheme}' not allowed). Solution: Use a publicly routable URL. For intentional internal access, fetch the data yourself and pass base64 content instead of a URL. Prevention: Do not set LANGCHAIN_ENV=local* in production to work around this.

Error: Loading from the deprecated github-based Hub is no longer supported. Please use the new LangChain Hub at https://smith.langchain.com/hub instead.

Cause: load_prompt("lc://..."). Solution: Pull prompts with the LangSmith SDK. Prevention: Remove lc:// references from configuration.

Error: Path '{path}' is absolute. Absolute paths are not allowed when loading prompt configurations to prevent path traversal attacks. …

Cause: A prompt config references an absolute template_path, examples or example_prompt_path (sibling error for .. components). Solution: Use relative paths, or pass allow_dangerous_paths=True only for trusted configs. Prevention: load_prompt is deprecated since 1.2.21 — migrate to dumps/loads.

Error: Loading templates with '{template_format}' format is no longer supported since it can lead to arbitrary code execution.

Cause: load_prompt on a jinja2 template file. Solution: Convert the template to f-string. Prevention: —

Error: jinja2 is unsafe and is not supported for templates expressed as dicts. Please use 'f-string' or 'mustache' format.

Cause: A dict-shaped message template with template_format="jinja2". Solution: Use f-string or mustache. Prevention: —

Error: Cannot traverse into {type}. … Mustache templates only support dict, list, and tuple. (TypeError)

Cause: A mustache variable path tried to read attributes of a non-container object (deliberately blocked). Solution: Convert objects to dicts before formatting. Prevention: Pass plain data into prompts.

Error: Batch size must be a positive integer, got {size}.

Cause: index(..., batch_size=0) or a negative cleanup_batch_size. Solution: Use positive values (defaults 100 and 1,000). Prevention: —

Error: time_at_least must be in the past

Cause: RecordManager.update(time_at_least=...) with a future timestamp, usually clock skew between hosts writing the same record manager. Solution: Synchronize clocks (NTP) across indexing workers. Prevention: Use the database time source of a SQL record manager for multi-host indexing.

Error: IDs must be provided for deletion

Cause: InMemoryDocumentIndex.delete() without ids. Solution: Pass the IDs to delete. Prevention: —

Error: _HashedDocument is an internal abstraction that was deprecated in langchain-core 0.3.63. …

Cause: Code imported the private _HashedDocument. Solution: Remove the dependency; use index()'s public API and key_encoder. Prevention: Avoid underscore-prefixed imports.

Error: delete method must be implemented by subclass.

Cause: index() with a cleanup mode on a vector store that does not implement delete. Solution: Use a vector store with delete support, or cleanup=None. Prevention: Check integration support before enabling cleanup.

Error: Source id key is required when cleanup mode is incremental or scoped_full.

Cause: incremental and scoped_full cleanup need source IDs to scope deletions. Solution: Pass source_id_key="source" (or a callable) and ensure every document has it in metadata. Prevention: Stamp metadata["source"] in loaders.

Error: config must be a list of the same length as inputs, but got {n} configs for {m} inputs

Cause: batch(inputs, config=[...]) length mismatch. Solution: Pass one config per input, or a single dict for all. Prevention: —

Error: Provided run_id be used only for the first element of the batch. (RuntimeWarning)

Cause: A single config with run_id used for a multi-input batch. Solution: Pass per-input configs with distinct run_ids, or drop run_id. Prevention: —

Error: Missing keys {keys} in config['configurable'] Expected keys are {expected}.

Cause: RunnableWithMessageHistory invoked without session_id (or custom history keys). Solution: Pass config={"configurable": {"session_id": "..."}}. Better: migrate to create_agent + checkpointer — this class is deprecated (removal 2.0.0). Prevention: —

Error: RunnableWithMessageHistory is deprecated. Use LangGraph's built-in persistence instead.

Cause: Deprecated since core 1.3.3. Solution: Use a LangGraph checkpointer and thread_id. Prevention: Plan removal before 2.0.0.

Error: astream_log is deprecated. Use astream instead.

Cause: Deprecated since 1.3.3 (removal 2.0.0), as is astream_events(version="v1"). Solution: Use astream, astream_events(version="v2"), or LangGraph stream modes. Prevention: —

Error: The dispatcher API does not accept additional keyword arguments.Please do not pass any additional keyword arguments, instead include them in the data field.

Cause: dispatch_custom_event(name, data, extra=...). Solution: Put extra values inside data. Prevention: —

Error: RuntimeError from dispatch_custom_event with no parent run (Python 3.10 async)

Cause: On Python 3.10 async code, the run context is not propagated automatically. Solution: Pass config= explicitly to adispatch_custom_event(name, data, config=config). Prevention: Upgrade to Python 3.11+ for context propagation.

Error: File is not open. Use FileCallbackHandler as a context manager.

Cause: FileCallbackHandler used after its file was closed or outside a with block. Solution: with FileCallbackHandler("run.log") as handler: .... Prevention: —

Error: If env_var is set, handle_class must also be set to a non-None value.

Cause: register_configure_hook(..., env_var=...) without handle_class. Solution: Provide the handler class that the env var should activate. Prevention: —

Error: No indexed run ID {run_id}. (TracerException)

Cause: A custom tracer received an end/error event for a run it never saw start (often mixed sync/async callbacks or a handler added mid-run). Solution: Attach tracers at the root call via config={"callbacks": [...]}. Prevention: Avoid adding tracers inside tools mid-run.

Error: Install grandalf to draw graphs: pip install grandalf.

Cause: agent.get_graph().draw_ascii() without grandalf (siblings: pygraphviz for PNG, pyppeteer for local Mermaid rendering, requests for the Mermaid.INK API). Solution: Install the named package, or use draw_mermaid() for text output. Prevention: —

Error: Failed to reach {base_url} API while trying to render your graph. Status code: {code}.

Cause: draw_mermaid_png() uses the external Mermaid.INK service by default. Solution: Allow outbound access, or render locally with draw_method=MermaidDrawMethod.PYPPETEER. Prevention: Avoid external rendering in restricted networks.

Error: Found duplicate subgraph '{subgraph}' -- this likely means that you're reusing a subgraph node with the same name.

Cause: Two nested agents/subgraphs share a name when drawing a Mermaid graph. Solution: Give each create_agent(..., name=...) a unique name. Prevention: —

Error: Unable to merge left={left!r} and right={right!r}. Both must be of type str, dict, or list, or else be two equal objects.

Cause: Merging streamed chunks whose additional_kwargs/response_metadata values have incompatible types (usually a nonstandard OpenAI-compatible server). Solution: Disable streaming for that provider (disable_streaming=True) or use a dedicated integration. Prevention: —

Error: Cannot concatenate ChatMessageChunks with different roles.

Cause: Aggregating chunks from different messages. Solution: Aggregate per message ID. Prevention: —

Error: WARNING! {field_name} is not default parameter. {field_name} was transferred to model_kwargs.

Cause: An unknown constructor argument was passed to a provider class (typo or a new API parameter). Solution: Fix the typo, or pass provider parameters via model_kwargs / extra_body intentionally. Prevention: Review warnings at startup.

Error: Found {field_name} supplied twice.

Cause: The same parameter was given both directly and in model_kwargs. Solution: Remove one. Prevention: —

Error: As of openai>=1.0.0, if deployment(or aliasazure_deployment) is specified then openai_api_base(or aliasbase_url) should not be.

Cause: Legacy Azure configuration mixing base_url and azure_deployment. Solution: Use azure_endpoint + azure_deployment + api_version (OPENAI_API_VERSION). Prevention: Keep validate_base_url=True.

Error: Azure AzureChatOpenAI fails with an API-version error on first call

Cause: AzureChatOpenAI has no default API version (unlike AzureOpenAIEmbeddings, which defaults to 2023-05-15); OPENAI_API_VERSION is unset. There is no AZURE_OPENAI_API_VERSION variable. Solution: Set OPENAI_API_VERSION or pass api_version=. Prevention: Include the API version in deployment configuration.

Error: Azure workload identity not used (authentication fails in Kubernetes)

Cause: Workload identity auto-auth runs only when no key/token/provider is configured, all of AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_FEDERATED_TOKEN_FILE are set, and azure.identity imports; a missing azure-identity package is silently ignored. Solution: pip install "langchain-openai[azure-identity]" and verify the three variables inside the pod. Prevention: Add an import check for azure.identity in your readiness probe.

Error: StreamChunkTimeoutError during async OpenAI streaming

Cause: No parsed chunk arrived within stream_chunk_timeout (default 120 s, env LANGCHAIN_OPENAI_STREAM_CHUNK_TIMEOUT_S); SSE keepalives do not reset the timer. Long reasoning pauses can trigger it. Solution: Raise the timeout for reasoning-heavy models, or catch and retry. Prevention: Tune per model class.

Error: OpenAITimeoutError / OpenAIConnectionError

Cause: Provider timeouts or dropped connections; both subclass core ModelTimeoutError/ModelConnectionError (retryable). Solution: ModelRetryMiddleware, timeout=, TCP keepalive variables. Prevention: —

Error: Response missing 'choices' key: {keys}

Cause: An OpenAI-compatible server returned an error body or an unexpected shape. Solution: Inspect the raw response; set include_response_headers=True to see request IDs. Prevention: Use a native integration where available.

Error: Got different types for token usage: {type} and {type}

Cause: An OpenAI-compatible server reports usage fields with inconsistent types. Solution: Set stream_usage=False or use a native integration. Prevention: —

Error: Cannot currently include response headers when response_format is specified.

Cause: include_response_headers=True together with streamed structured output (a warning). Solution: Drop one of the two for that call. Prevention: —

Error: `access_token` must be a non-empty string.

Cause: Experimental ChatGPT OAuth tokens file is incomplete (sibling: refresh_token). Solution: Re-run the login flow; the file is ~/.langchain/chatgpt-auth.json. Prevention: This path is private and experimental — do not depend on it in production.

Error: _ChatOpenAICodex is experimental and unofficial. …

Cause: The private Codex chat class warns on use. Solution: Use only where permitted by your OpenAI account and workspace terms. Prevention: Prefer public classes.

Error: Could not import transformers python package. This is needed for OpenAIEmbeddings to work without tiktoken.

Cause: OpenAIEmbeddings(tiktoken_enabled=False) needs transformers for length-safe chunking. Solution: Install transformers, or re-enable tiktoken. Prevention: —

Error: tiktoken download failures in air-gapped environments

Cause: tiktoken fetches encodings on first use (the OpenAI package's own Makefile pre-downloads cl100k_base and o200k_base into TIKTOKEN_CACHE_DIR for this reason). Solution: Pre-populate a cache directory and set TIKTOKEN_CACHE_DIR. Prevention: Bake the cache into your image.

Error: Anthropic's legacy count_tokens method was removed in anthropic 0.39.0 and langchain-anthropic 0.3.0.

Cause: AnthropicLLM.get_num_tokens(). Solution: Use ChatAnthropic(...).get_num_tokens_from_messages(...). Prevention: Migrate from AnthropicLLM to ChatAnthropic.

Error: The 'output_format' parameter is deprecated and will be removed in langchain-anthropic 2.0.0. Use 'output_config={"format": ...}' instead.

Cause: Old structured-output parameter. Solution: Use output_config. Prevention: —

Error: Tool-change block {type!r} was dropped: it is only valid on a SystemMessage sent in place …

Cause: tool_addition/tool_removal system blocks hoisted into the top-level system prompt on a model without mid-conversation system support. Solution: Use a model that supports mid-conversation system messages. Prevention: —

Error: AnthropicPromptCachingMiddleware caching middleware only supports Anthropic models, not instances of {type}

Cause: The middleware ran with a non-ChatAnthropic model (for example after ModelFallbackMiddleware switched providers). Default behavior is a warning; "raise" makes it an error. Solution: Set unsupported_model_behavior="ignore" for multi-provider agents. Prevention: Same applies to FireworksPromptCachingMiddleware (only supports ChatFireworks).

Error: AnthropicPromptCachingMiddleware requires 'langchain' to be installed.

Cause: Provider middleware imported without the langchain agents package (similarly for Fireworks). Solution: pip install langchain. Prevention: —

Error: Path must start with one of {allowed_prefixes}: {path}

Cause: A Claude text-editor/memory tool call outside the allowed prefixes (memory defaults to /memories). Solution: Adjust allowed_path_prefixes if the access is legitimate. Prevention: Keep prefixes narrow.

Error: File not found: {path}

Cause: State-backed Claude text-editor/memory tool viewed a file absent from state. Solution: None — the model receives the error. For persistence across threads use the filesystem variants. Prevention: —

Error: Received an error from the Ollama API. Please check your Ollama server logs.

Cause: Ollama rejected list() during validate_model_on_init. Solution: Check ollama serve logs and the server version. Prevention: —

Error: Image data only supported through in-line base64 format.

Cause: ChatOllama received an image URL block. Solution: Download and pass base64 data. Prevention: —

Error: `stop` found in both the input and default params.

Cause: ChatOllama(stop=[...]) plus a per-call stop=. Solution: Set stop sequences in one place. Prevention: —

Error: `top_logprobs` must be a positive integer.

Cause: Invalid ChatOllama(top_logprobs=0). Setting top_logprobs without logprobs auto-enables logprobs with a warning; with logprobs=False it raises. Solution: Use a value ≥ 1 and leave logprobs unset or True. Prevention: —

Error: Could not download mistral tokenizer from Huggingface for calculating batch sizes. Set a Huggingface token via the HF_TOKEN environment variable …

Cause: MistralAIEmbeddings tried to download the gated mistralai/Mixtral-8x7B-v0.1 tokenizer. Solution: Set HF_TOKEN with access, or accept the len() fallback batching. Prevention: Pre-cache the tokenizer in images.

Error: `repo_id` must be a HuggingFace repo ID, not a URL. Use `endpoint_url` for direct endpoints.

Cause: A URL was passed as repo_id to HuggingFaceEndpoint (or embeddings model/repo_id). Solution: Use endpoint_url= for URLs. Prevention: —

Error: Backend: {backend} requires optimum-intel>={version}.

Cause: HuggingFacePipeline.from_model_id(backend="openvino"/"ipex") without the required optimum-intel. Solution: pip install --upgrade --upgrade-strategy eager "optimum[{backend}]". Prevention: —

Error: `backend='ipex'` is no longer supported; the default `torch` backend will be used instead.

Cause: HuggingFaceEmbeddings(model_kwargs={"backend": "ipex"}). Solution: Remove the setting; PyTorch 2.5+ supports Intel GPUs natively. Prevention: —

Error: At least one HumanMessage must be provided! / Last message must be a HumanMessage!

Cause: ChatHuggingFace builds a chat-template prompt that must end with a human turn. Solution: Ensure the final message is a HumanMessage. Prevention: —

Error: Fireworks received an invalid payload: {text} / Fireworks Server: Error {status}

Cause: The legacy Fireworks completion LLM got a 4xx/5xx response. Solution: Check the model name and parameters; retry 5xx. Prevention: Prefer ChatFireworks.

Error: FIREWORKS_API_KEY is required unless both client and async_client are supplied.

Cause: FireworksRerank without credentials. Solution: Set the variable or pass clients. Prevention: —

Error: DeepSeek API returned an invalid response. Please check the API status and try again.

Cause: Non-JSON streaming data from DeepSeek. Solution: Retry; check provider status. Prevention: ModelRetryMiddleware.

Error: `extra_body` must be a dict to forward Perplexity-specific parameters to the Responses API …

Cause: A non-dict extra_body on ChatPerplexity routed to the Responses API. Solution: Pass a dict. Prevention: Note that on that path temperature, top_p, top_k, stop and metadata are dropped with a warning, and tool_choice raises.

Error: Parameters {params} should be specified explicitly. Instead they were passed in as part of model_kwargs parameter.

Cause: Known fields were placed in model_kwargs (Perplexity and others). Solution: Pass them as constructor arguments. Prevention: —

Error: Could not import the openrouter Python SDK. Please install it with: pip install openrouter

Cause: Broken install of langchain-openrouter (it uses the official OpenRouter SDK, not openai). Solution: Reinstall the package. Prevention: —

Error: Must provide tenant and database values to connect to Chroma Cloud

Cause: Chroma(chroma_cloud_api_key=...) without tenant/database. Solution: Provide both. Prevention: —

Error: Chroma collection not initialized. Use reset_collection to re-create and initialize the collection.

Cause: The collection was deleted (delete_collection()) and then used. Solution: Call reset_collection(). Prevention: —

Error: {message}\n\nTry filtering complex metadata using langchain_community.vectorstores.utils.filter_complex_metadata.

Cause: Chroma rejects nested/complex metadata values. Solution: Flatten metadata or apply filter_complex_metadata. Prevention: Keep metadata scalar.

Error: client should be an instance of qdrant_client.QdrantClient, got {type}

Cause: The legacy Qdrant class received a wrong client object. Solution: Migrate to QdrantVectorStore(client=QdrantClient(...), collection_name=..., embedding=...) — Qdrant is deprecated. Prevention: —

Error: Sparse embeddings are None. Please set using the sparse_embedding parameter.

Cause: QdrantVectorStore(retrieval_mode=RetrievalMode.SPARSE/HYBRID) without sparse_embedding. Solution: Pass sparse_embedding=FastEmbedSparse(). Prevention: —

Error: Embeddings are required for {operation}

Cause: Dense operations on a QdrantVectorStore created without embedding. Solution: Provide embedding=. Prevention: —

Error: Using dict as a filter is deprecated. Please use qdrant-client filters directly

Cause: Legacy dict filters on Qdrant. Solution: Use qdrant_client.models.Filter. Prevention: —

Error: Unknown distance strategy, must be COSINE, DOT, or EUCLID.

Cause: Unsupported distance for relevance scoring. Solution: Use a supported distance or pass relevance_score_fn. Prevention: —

Error: Language {language} is not implemented yet!

Cause: RecursiveCharacterTextSplitter.from_language() with a Language enum member that has no separator set. Solution: Pass custom separators=. Prevention: —

Error: Unable to import lxml, please install with pip install lxml.

Cause: HTMLSectionSplitter needs lxml (and bs4). Solution: Install both. Prevention: Text-splitters declares no extras — list optional deps explicitly.

Error: ❌ Provider '{provider}' not found in models.dev data / Continue? (y/N): prompt in CI (langchain-profiles)

Cause: The provider ID is not a models.dev ID (e.g. mistral not mistralai, fireworks-ai not fireworks), or --data-dir is outside the current directory in a non-interactive job. Solution: Use models.dev IDs (see libs/model-profiles/Makefile), and pipe echo y | for out-of-tree data dirs. Prevention: Use make refresh-profiles.

Error: Profile keys not declared in langchain_core ModelProfile: {extra}. Add these fields to langchain_core.language_models.model_profile.ModelProfile and release langchain-core before publishing partner packages …

Cause: models.dev or augmentations introduced a new capability key. Solution: Add the field to ModelProfile and release core first. Prevention: Release core before partners that depend on new profile keys.

Error: Could not parse profile source as Python: {e} / `_PROFILES` is not a literal expression

Cause: langchain-profiles summarize found a hand-edited or corrupted _profiles.py. Solution: Regenerate with refresh; never edit _profiles.py by hand. Prevention: —

Error: Unknown lib: … check_diff.py likely needs an update for this new library!

Cause: A PR added a new directory under libs/ that CI change detection does not know. Solution: Update .github/scripts/check_diff.py (and the other files listed for new partners in AGENTS.md). Prevention: Follow the "Adding a new partner to CI" checklist.

Error: PR title check fails in pr_lint.yml

Cause: Title not in Conventional Commit form with an allowed scope, uppercase scope, or release used as a scope. Solution: Use type(scope): lowercase description, e.g. fix(openai): handle null choices. Prevention: Check the allowed scopes in Section 10.5.

Cause: require_issue_link.yml closes external PRs that do not link an approved issue assigned to the author. Solution: Link the issue and get assigned; reopen_on_assignment.yml reopens the PR. Prevention: Open an issue first.

Error: pytest_socket.SocketBlockedError in unit tests

Cause: Unit tests run with --disable-socket --allow-unix-socket; a test made a network call. Solution: Mock the network or move the test to tests/integration_tests/. Prevention: Keep unit tests hermetic.

Error: blockbuster.BlockingError in async unit tests

Cause: blockbuster detected a blocking call (file I/O, time.sleep) inside async code. Solution: Use async equivalents or run_in_executor. Prevention: —

Error: CassetteNotFoundError in VCR tests

Cause: test_vcr runs with --record-mode=none and the cassette was never recorded. Solution: Record locally against the live API with credentials, commit the gzip-compressed YAML cassette under tests/cassettes. Prevention: Review cassettes for secrets before committing.

Error: test_no_overrides_DO_NOT_OVERRIDE fails in an integration package

Cause: A standard test was removed or overridden without @pytest.mark.xfail(reason="..."). Solution: Restore it, or mark the override with xfail and a reason. Prevention: —

Error: uv lock --check fails (make check-lock)

Cause: pyproject.toml changed without re-locking. Solution: cd libs/<pkg> && uv lock; revert unrelated environment-marker churn from different local Python versions. Prevention: UV_FROZEN=true in Makefiles surfaces this early.

Error: Version-check pre-commit hook fails (make check_version)

Cause: pyproject.toml version and _version.py/version.py differ. Solution: Bump both (and uv.lock) in the same release PR. Prevention: Use the release(<pkg>): <version> PR pattern.

Error: This module has been moved to langchain-experimental. … pip install langchain-experimental

Cause: LLMBashChain, Python REPL tools and similar dangerous components were removed from langchain-classic. Solution: Use langchain-experimental inside a sandbox, or a ShellToolMiddleware with a Docker policy. Prevention: —

Error: Importing from {module} is not allowed. Allowed top-level packages are: …

Cause: A langchain_classic compatibility shim tried to import from an unexpected package. Solution: Import the target class from its real package directly. Prevention: Migrate off langchain_classic re-exports.

Error: Cannot specify both callback_manager and callbacks.

Cause: Classic chains given the deprecated callback_manager and callbacks. Solution: Use callbacks only. Prevention: —

Error: A single string input was passed in, but this chain expects multiple inputs ({keys}).

Cause: A classic multi-input chain called with a string. Solution: Pass a dict with all input keys. Prevention: Migrate classic chains to LCEL or agents.

Error: The same variables {overlap} are found in multiplememory object, which is not allowed by CombinedMemory.

Cause: Two classic memory classes expose the same variable. Solution: Rename memory keys — or migrate to a checkpointer (classic memory is deprecated). Prevention: —

Error: Could not import upstash_redis python package.

Cause: Classic entity memory with the Upstash back end. Solution: pip install upstash_redis. Prevention: —

Error: HostExecutionPolicy commands run as the service user with full access

Cause: Default shell policy is HostExecutionPolicy (no sandbox). Solution: Switch to DockerExecutionPolicy or CodexSandboxExecutionPolicy. Prevention: Make an explicit execution_policy mandatory in code review.

Error: Codex sandbox policy could not determine a supported platform; set 'platform' explicitly.

Cause: Neither macOS nor Linux detected. Solution: Set platform="linux" or "macos", or use Docker. Prevention: —

Error: Failed to apply resource limits via prlimit.

Cause: The container or kernel forbids prlimit on the child process. Solution: Remove cpu_time_seconds/memory_bytes, or enforce limits via cgroups/container settings. Prevention: —

Error: This version of FastMCP does not expose Client._await_with_session_monitoring, so an MCP elicitation round cannot be raced against the session task. (RuntimeWarning)

Cause: Version skew between fastmcp and langchain; a transport failure during elicitation could hang. Solution: Install fastmcp within the range pinned by langchain[mcp] (>=4.0.1,<5.0.0). Prevention: Upgrade langchain and fastmcp together.

Error: This MCP server asked for input over the legacy server-initiated elicitation path, which interrupt-based elicitation cannot answer.

Cause: The server uses the legacy elicitation path rather than returning InputRequiredResult. Solution: Upgrade the server, or supply your own FastMCP client with an elicitation callback. Prevention: —


12. Potential Improvements

Findings from reading the source at a9780cd plus open GitHub issues captured in the briefing.

12.1 Defects and inconsistencies found in source

Area Finding Location
Error message RunnablePick reports non-dict input with the message for RunnablePassthrough.assign() libs/core/langchain_core/runnables/passthrough.py:754
Docstrings Anthropic middleware examples import StateTextEditorToolMiddleware, StateMemoryToolMiddleware, FilesystemTextEditorToolMiddleware, FilesystemMemoryToolMiddleware from langchain.agents.middleware; none exist libs/partners/anthropic/langchain_anthropic/middleware/anthropic_tools.py, file_search.py
Docstrings Core tool docstrings show from langchain_core.tools import tool, ToolRuntime; ToolRuntime is exported from langchain.tools (LangGraph), not core libs/core/langchain_core/tools/base.py
Docs drift langchain-profiles README and refresh docstring say it writes profiles.py; code writes _profiles.py libs/model-profiles
Docs drift langchain-typesafe README imports TypeSafeRateLimitError from the package root; it lives in langchain_typesafe.client libs/partners/typesafe
Validation gap InMemoryRateLimiter docstring requires max_bucket_size >= 1, but nothing enforces it libs/core/langchain_core/rate_limiters.py
Defaults ChatOpenAI.model_name still defaults to gpt-3.5-turbo; OpenAIEmbeddings to text-embedding-ada-002 libs/partners/openai
Defaults index() defaults to SHA-1 keys and only warns libs/core/langchain_core/indexing/api.py
Deprecation hygiene Legacy Qdrant is marked removal="0.5.0" but still exported at 1.1.0 libs/partners/qdrant
Consistency ChatPerplexity reads only PPLX_API_KEY while sibling classes accept PERPLEXITY_API_KEY; MistralAIEmbeddings ignores MISTRAL_BASE_URL; ChatOllama ignores OLLAMA_HOST partner packages
Consistency @tool defaults error_on_invalid_docstring=True; StructuredTool.from_function defaults False libs/core/langchain_core/tools/
Silent failure Profile resolution errors in BaseChatModel are suppressed; Azure workload identity silently disables itself without azure-identity core, langchain-openai
Governance No SECURITY.md / disclosure policy; bug template references an undefined "security option" repo root, .github/ISSUE_TEMPLATE

12.2 Open issues worth tracking (from the briefing's GitHub snapshot)

Issue Summary
#40492 after_model middleware using jump_to="tools" bypasses the HITL gate and can re-execute rejected tool calls
#40688 ToolRetryMiddleware defaults retry non-idempotent tools on ambiguous transport errors
#40767 PIIMiddleware(apply_to_output=True) blanks tool-call parameters, leading to graph recursion errors
#40826 Streaming a large tool call re-parses arguments in pure Python on every chunk
#40877 RunnableParallel ignores max_concurrency on ainvoke/astream
#40878 with_fallbacks(exception_key=...) writes the exception into the caller's input mapping
#40879 InjectedToolCallId overridden by a value in args when a custom args_schema omits the field
#40880 Pydantic-aliased injected args not filtered from on_tool_start inputs
#40881 on_tool_error does not receive caller **kwargs
#39900 MarkdownListOutputParser drops + bullet items (its pattern only matches - and *)
#40871 OpenAI Responses stream IDs switch from resp_… to lc_run--…
#40892 ChatAnthropic drops message-level output_config and clear_at from SystemMessage
#40896 / #40895 / #40897 ChatOpenAI forwards unsupported stop/sampling parameters to some reasoning models; Qwen named tool_choice rejected in thinking mode
#40909 / #40915 / #40914 Stream crashes on null tool-call deltas (OpenAI) and TypeError in ChatPerplexity.stream()
#40866 ModelCallLimitMiddleware limit message indistinguishable from a model answer
#40158 Proposed opt-in tool-call verification hook
#40825 Support for MCP Apps (SEP-1865)

12.3 Suggested improvements

  1. Publish a SECURITY.md with a disclosure channel and the threat model already written into load/load.py and _security/.
  2. Change load's default allowed_objects to "messages" (already signaled by the pending deprecation) and make index() default to a collision-resistant key encoder.
  3. Make ToolRetryMiddleware's default retry_on conservative (transport-safe exceptions only) and document idempotency.
  4. Add an explicit, typed marker to limit-exceeded AI messages (#40866) so applications can distinguish them.
  5. Emit a warning when SummarizationMiddleware is constructed without a trigger, since it otherwise never runs.
  6. Honor OLLAMA_HOST in ChatOllama and PERPLEXITY_API_KEY in ChatPerplexity for parity with SDK conventions.
  7. Fix the stale docstring imports and README drift listed above; add a doc-test that imports every example symbol.
  8. Validate InMemoryRateLimiter(max_bucket_size>=1).

13. Quick Reference

13.1 Key paths

Path Contents
libs/langchain_v1/langchain/agents/factory.py create_agent
libs/langchain_v1/langchain/agents/middleware/ Middleware types and implementations
libs/langchain_v1/langchain/chat_models/base.py init_chat_model and provider registry
libs/langchain_v1/langchain/mcp/ MCP adapter
libs/core/langchain_core/runnables/base.py Runnable protocol
libs/core/langchain_core/language_models/chat_models.py BaseChatModel
libs/core/langchain_core/load/load.py Deserialization and its threat model
libs/core/langchain_core/_security/ SSRF policy and transports
libs/partners/<p>/langchain_<p>/data/_profiles.py Generated model profiles
libs/standard-tests/langchain_tests/ Conformance suites
.github/workflows/_release.yml Release pipeline
.github/scripts/check_diff.py CI change detection
AGENTS.md Contributor rules

13.2 Commands

# Development (run inside a package directory)
cd libs/langchain_v1 && uv sync --all-groups
make test            # unit tests (no network)
make lint && make format
uv run --group lint mypy .
make integration_tests

# Monorepo-wide lockfiles
make -C libs lock
make -C libs check-lock

# Model profiles
cd libs/model-profiles && make refresh-profiles

# Release (maintainers)
gh workflow run 63880841 --repo langchain-ai/langchain -f working-directory=<partner> -f release-version=<version>

# Diagnostics
python -m langchain_core.sys_info

13.3 Critical settings

Setting Value to remember
Agent graph recursion limit 9,999 (set by create_agent)
Runnable recursion_limit default 25
ModelRetryMiddleware / ToolRetryMiddleware 2 retries, ×2 backoff from 1 s, max 60 s, ±25% jitter
SummarizationMiddleware no default trigger; keeps 20 messages; trims 4,000 tokens for the summary call
ClearToolUsesEdit trigger 100,000 tokens, keep 3, placeholder [cleared]
Shell policy timeouts command 30 s, startup 30 s, termination 10 s, 100 output lines
Docker policy image python:3.12-alpine3.19, network off
FilesystemFileSearchMiddleware max file 10 MB, ripgrep preferred
OpenAI stream chunk timeout 120 s (async)
load() default allowed_objects="core" (unsafe for untrusted data), secrets_from_env=False
index() default key_encoder="sha1", batch_size=100, cleanup_batch_size=1000
Python ≥ 3.10

13.4 Ports and endpoints

LangChain listens on no ports. Endpoints referenced by default configuration: https://api.anthropic.com, https://api.x.ai/v1/, https://api.deepseek.com/v1 (/beta for strict mode), https://api.mistral.ai/v1, https://api.fireworks.ai/inference/v1, https://api.typesafe.ai, https://gateway.smith.langchain.com (gateway), https://models.dev/api.json (profile CLI), Ollama SDK default host, Chroma HttpClient port 8000.