langchain correction pack · for projects on langchain>=1,<2 (Python)
What we actually measured
5 Claude models were asked for idiomatic langchain code with no tools, purely from training knowledge. 20 reproduced failures across 22 runs, each verified against the release that broke the belief.
| Model | Stated cutoff | langchain version attribution stops | Lag inside the window |
|---|---|---|---|
| Claude Opus 5 | 2026-05 | 1.0.0 · 2025-10-17 | ~7 months |
| Claude Fable 5.1 | 2026-06 | 1.1.0 · 2025-11-24 | ~6 months |
| Claude Haiku 4.5 | 2025-02 | 0.3.0 · 2024-09-13 | ~5 months |
| Claude Fable 5 | 2026-01 | 1.0.0 · 2025-10-17 | ~3 months |
| Claude Sonnet 5 | 2026-01 | 1.0.0 · 2025-10-17 | ~3 months |
A recent cutoff is not a defence. Every model here loses track of this library's release history well before the date it states as its own cutoff, and the stopping points cluster far tighter than the cutoffs do.
Read that column precisely. It is the newest langchain release whose contents the model can correctly attribute to that release — not the newest langchain feature it knows. Past that point a model will often write working code with a newer API while naming the wrong release for it, and that guess runs early — it names a release older than the one that shipped the feature. So the question this pack answers is not "does the model know this API" but "can it be trusted about which version the API arrived in" — which is the question that matters when you are pinned to a version.
Latest langchain is 1.4.0 (verified 2026-09-06). Separately from the corrections below, 3 of 22 runs recorded a version fact — the model named a current langchain version from memory and was behind. If a model states a version without checking, assume it is behind and check the registry.
How to read an entry
Every entry ends with a Reproduced against line. Where it names models, we have the generated code that got it wrong, dated, with the model's own words in the run write-up. Where it says no model yet, the correction is verified from the release notes but nothing has been probed for it — it is a fix, not a measurement, and the pack says so rather than blurring the two.
The section an entry sits in is the worst case if you act on the stale belief. The severity in brackets after a model's name is what that particular model's output actually did, which can be milder — a model can hold the wrong belief and still, on the day, write code that runs.
The corrections
Breaks the build, or throws at runtime
Act on the stale belief here and the code does not run. Fix these first.
langchain.hub
Removed in langchain 1.0.0 (2025-10-17)
from langchain import hub no longer works. The hub module moved to langchain-classic; the prompt registry is also reachable directly from the LangSmith SDK, which is the path the current docs use.
The stale belief: That the hosted prompt registry is reached with from langchain import hub; hub.pull("owner/name"), optionally after pip install langchainhub.
# Stale
from langchain import hub
prompt = hub.pull("hwchase17/react")
# Current
# pip install langchain-classic
from langchain_classic import hub
prompt = hub.pull("hwchase17/react")
# or, without the compatibility package:
# pip install langsmith
from langsmith import Client
prompt = Client().pull_prompt("hwchase17/react")
Reproduced against: Claude Sonnet 5 (S1) — langchain/v1, 2026-08-31.
Source: LangChain v1 migration guide — update your imports · API reference — langchain_classic.hub.pull
agent custom state
Stricter in langchain 1.0.0 (2025-10-17)
Custom agent state must be a TypedDict. The Pydantic state classes are gone: AgentStatePydantic and AgentStateWithStructuredResponsePydantic have no replacement beyond langchain.agents.AgentState.
The stale belief: That agent state can be declared as a Pydantic model.
# Stale
from langgraph.prebuilt.chat_agent_executor import AgentStatePydantic
# Current
from typing_extensions import TypedDict
from langchain.agents import AgentState
class MyState(AgentState):
tickets: list[str]
Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.
Source: LangChain v1 migration guide — Custom state · LangGraph v1 migration guide — Deprecations
AIMessage(example=...)
Removed in langchain 1.0.0 (2025-10-17)
The example parameter was removed from AIMessage. Put that metadata in additional_kwargs.
The stale belief: That AIMessage(content=..., example=True) is valid.
# Stale
AIMessage(content="...", example=True)
# Current
AIMessage(content="...", additional_kwargs={"example": True})
Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.
Source: LangChain v1 migration guide — example parameter removed from AIMessage
create_agent(pre_model_hook=...) / post_model_hook
Removed in langchain 1.0.0 (2025-10-17)
pre_model_hook and post_model_hook are not create_agent parameters. Their replacement is middleware: a before_model / after_model hook, or wrap_model_call when you want to change only what is sent to the model without editing stored state.
The stale belief: That message trimming or output validation is wired in with pre_model_hook= / post_model_hook= on the agent factory.
# Stale
agent = create_agent(model, tools, pre_model_hook=trim)
# Current
from langchain.agents.middleware import wrap_model_call
@wrap_model_call
def trim(request, handler):
return handler(request.override(messages=request.messages[-6:]))
agent = create_agent(model, tools, middleware=[trim])
Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.
Source: LangChain v1 migration guide — Pre-model hook · API reference — langchain.agents.middleware.wrap_model_call
create_agent(response_format=...)
Removed in langchain 1.0.0 (2025-10-17)
Prompted structured output — passing a (instruction_string, Schema) tuple to response_format — was removed. A bare schema is still accepted, and the framework picks a strategy; to choose explicitly, pass ToolStrategy(Schema) (artificial tool call, works on any tool-calling model) or ProviderStrategy(Schema) (provider-native constrained decoding). The result lands in result["structured_response"].
The stale belief: That you can steer structured output by handing response_format a prompt alongside the schema.
# Stale
agent = create_react_agent(model, tools,
response_format=("please generate ...", OutputSchema))
# Current
from langchain.agents.structured_output import ToolStrategy
agent = create_agent(model, tools, response_format=ToolStrategy(OutputSchema))
result["structured_response"]
1.0.0 also stopped generating structured output in a separate graph node; it happens in the main loop, which removes an extra model call. 1.2.0 (2025-12-15) added strict schema adherence for
ProviderStrategy.
Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.
Source: LangChain v1 migration guide — Prompted output removed · LangChain changelog — langchain v1.2.0 · 2025-12-15
create_agent(system_prompt=...)
Renamed in langchain 1.0.0 (2025-10-17)
The static instruction parameter is system_prompt. prompt= was the create_react_agent name and is not accepted by create_agent — passing it raises TypeError: unexpected keyword argument.
The stale belief: That the agent factory takes prompt=.
# Stale
agent = create_agent(model, tools, prompt="You are helpful.")
# Current
agent = create_agent(model, tools, system_prompt="You are helpful.")
1.0.0 required a plain string here; 1.1.0 (2025-11-24) added support for passing a
SystemMessageinstance, which enables cache control and structured content blocks.
Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.
Source: LangChain v1 migration guide — Static prompt rename · LangChain changelog — langchain v1.1.0 · 2025-11-25
langchain text splitters
Removed in langchain 1.0.0 (2025-10-17)
Text splitters are not part of the v1 langchain namespace. They live in their own distribution, langchain-text-splitters, imported as langchain_text_splitters.
The stale belief: That from langchain.text_splitter import RecursiveCharacterTextSplitter works.
# Stale
from langchain.text_splitter import RecursiveCharacterTextSplitter
# Current
# pip install langchain-text-splitters
from langchain_text_splitters import RecursiveCharacterTextSplitter
Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.
Source: What's new in LangChain v1 — Namespace
langchain-classic
New requirement in langchain 1.0.0 (2025-10-17)
langchain-classic is a separate distribution. pip install langchain does not bring it in, so every legacy import above fails with ModuleNotFoundError: No module named 'langchain_classic' until it is installed. Any migration advice that only rewrites the import path is incomplete without the install line.
The stale belief: That legacy symbols are still reachable from whatever is installed alongside langchain.
# Stale
pip install langchain
# Current
pip install langchain langchain-classic
First published to PyPI 2025-10-07 (1.0.0a1); 1.0.8 is the latest as of 2026-08-31.
Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.
Source: LangChain v1 migration guide — Install with · PyPI JSON API — langchain-classic release timestamps
langchain.agents.initialize_agent / AgentExecutor
Removed in langchain 1.0.0 (2025-10-17)
initialize_agent, AgentExecutor and AgentType are gone from langchain.agents, which now exports create_agent and AgentState. The old agent machinery is in langchain-classic.
The stale belief: That agents are built with initialize_agent(tools, llm, agent=AgentType.OPENAI_FUNCTIONS) or by wrapping a runnable in an AgentExecutor.
# Stale
from langchain.agents import initialize_agent, AgentType, AgentExecutor
# Current
from langchain.agents import create_agent
These were deprecated long before 1.0.0; 1.0.0 is where they left the package.
Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.
Source: API reference — langchain_classic.agents.initialize.initialize_agent · What's new in LangChain v1 — Namespace
langchain.chains (LLMChain, ConversationChain, RetrievalQA)
Removed in langchain 1.0.0 (2025-10-17)
Legacy chains are not in the langchain package. They moved to langchain-classic, which pip install langchain does not install, so from langchain.chains import LLMChain is an ImportError on a fresh v1 environment. Either install langchain-classic and import from langchain_classic.chains, or write the pipeline directly — a prompt piped into a model, or a retrieve-then-answer function.
The stale belief: That LLMChain, ConversationChain, RetrievalQA and friends live in langchain.chains.
# Stale
from langchain.chains import LLMChain, RetrievalQA
# Current
# only if you really need the legacy chain:
# pip install langchain-classic
from langchain_classic.chains import LLMChain, RetrievalQA
Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.
Source: LangChain v1 migration guide — langchain-classic · API reference — langchain_classic.chains.llm.LLMChain
langchain.memory (ConversationBufferMemory)
Removed in langchain 1.0.0 (2025-10-17)
The memory classes are not in langchain. Conversation memory in v1 is a LangGraph checkpointer keyed by thread_id, not an object hung off a chain; the old classes remain available only in langchain-classic.
The stale belief: That you attach memory=ConversationBufferMemory(...) to a chain.
# Stale
from langchain.memory import ConversationBufferMemory
chain = ConversationChain(llm=llm, memory=ConversationBufferMemory())
# Current
from langgraph.checkpoint.memory import InMemorySaver
agent = create_agent(model, tools, checkpointer=InMemorySaver())
cfg = {"configurable": {"thread_id": "session-1"}}
agent.invoke({"messages": [...]}, cfg)
Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.
Source: API reference — langchain_classic.memory.buffer.ConversationBufferMemory · LangChain v1 migration guide — langchain-classic
langchain.retrievers / langchain.indexes
Removed in langchain 1.0.0 (2025-10-17)
Retrievers and the indexing API left the langchain namespace for langchain-classic. A vector store's own .as_retriever() is unaffected and is the normal way to retrieve in v1.
The stale belief: That from langchain.retrievers import ... and from langchain.indexes import ... resolve.
# Stale
from langchain.retrievers import MultiQueryRetriever
from langchain.indexes import index
# Current
# pip install langchain-classic
from langchain_classic.retrievers import MultiQueryRetriever
from langchain_classic.indexes import index
Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.
Source: LangChain v1 migration guide — langchain-classic
pre-bound models
Removed in langchain 1.0.0 (2025-10-17)
create_agent does not accept a model that already has tools bound to it. Pass the model and the tools separately, and vary the model per call with middleware (wrap_model_call + request.override(model=...)) if you need dynamic selection.
The stale belief: That you can hand the agent factory model.bind_tools([...]).
# Stale
agent = create_agent(model.bind_tools(tools), tools)
# Current
agent = create_agent(model, tools)
Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.
Source: LangChain v1 migration guide — Model
Runs, but is silently wrong
Nothing errors. The behaviour is simply not what a model trained earlier will tell you.
tool extras
Added in langchain 1.2.0 (2025-12-15)
Provider-specific tool parameters go in extras, a flat dict[str, Any] on the tool — @tool(extras={...}) or the extras attribute on a tool object. The keys are the provider's own field names (defer_loading, cache_control, input_examples), NOT a provider name wrapping them. There is no provider_specific attribute, and metadata= is a different field that goes to callback handlers and never reaches the provider payload.
The stale belief: That provider-specific tool configuration has no first-class home on a tool, so it must be smuggled in by binding raw provider-format tool dicts, or hung on whichever tool field looks closest.
# Stale
# stale, and silent: no such attribute. Pydantic accepts the assignment on the
# tool object and nothing downstream ever reads it.
tool_obj.provider_specific = {"anthropic": {"defer_loading": True}}
# stale, and silent: `metadata` is a real BaseTool field, but it goes to callback
# handlers and is never serialised into the tool definition sent to the provider.
# (As a DECORATOR keyword this one is not silent -- `@tool(metadata=...)` raises
# TypeError, because the decorator has never taken `metadata`.)
tool_obj.metadata = {"cache_control": {"type": "ephemeral"}}
# stale, and silent: right attribute, wrong shape. langchain-anthropic copies
# across only keys in its own whitelist, so an "anthropic" wrapper key is dropped.
@tool(extras={"anthropic": {"defer_loading": True}})
def u(x: str) -> str: ...
# stale, but NOT broken: rebuilding the provider's tool dict by hand and splicing
# the fields in does reach the wire. It costs you the tool defined twice, the name
# kept in sync by hand, and a separate lookup to execute the call the model returns.
fn = convert_to_openai_tool(search_docs)["function"]
model.bind_tools([{ "name": fn["name"], "description": fn["description"],
"input_schema": fn["parameters"],
"cache_control": {"type": "ephemeral"}, "defer_loading": True }])
# Current
@tool(extras={"defer_loading": True, "cache_control": {"type": "ephemeral"}})
def my_tool(x: str) -> str:
...
The wrong forms above are not hypothetical: the first three are what Opus 5, Sonnet 5 and Fable 5 respectively produced on 2026-09-01 (battery langchain/v2), and the fourth is what four of six draws produced on 2026-09-06 (battery langchain/v6). Raised from S4 to S2 in 2026-09 because three of three tested models got it wrong and the failure is silent: the code runs and the provider instruction is discarded. Two corrections to this note, both from executing the forms rather than reading them (2026-09-06, JOURNAL/065). (1) It previously said all three forms "fail the same way -- nothing raises". That is true of the two attribute forms, verified against langchain-core 1.6.2:
tool_obj.metadata = {...}and@tool(extras={"anthropic": {...}})both leaveconvert_to_anthropic_tooloutput with nocache_controland nodefer_loading. It is NOT true of@tool(metadata={...})as a decorator keyword, which raisesTypeError: tool() got an unexpected keyword argument 'metadata'-- the decorator has never acceptedmetadata, so that form is loud, not silent, and the example above is rewritten as the attribute assignment that actually is silent. (2) A fourth wrong form exists and it WORKS: hand-rebuilding the provider's tool dict and splicing the fields in delivers both, becauseAnthropicToolis a TypedDict and an already-Anthropic-shaped dict is copied whole. Findings charged off that form are scored S3, not S2. The mechanism, verified in langchain-anthropic 1.7.1chat_models.py:convert_to_anthropic_tooliteratestool.extrasand copies across only keys in_ANTHROPIC_EXTRA_FIELDS= {allowed_callers, cache_control, defer_loading, eager_input_streaming, input_examples}, placing each at the top level of the tool definition. Re-verified 2026-09-06 against the shipped langchain-core 1.6.2 and langchain-anthropic 1.7.1; absent from langchain-core 1.1.3 and 0.3.22.
Reproduced against: Claude Fable 5 (S2), Claude Opus 5 (S2), Claude Sonnet 5 (S2) — langchain/v2, 2026-09-01; langchain/v6-a, 2026-09-06; langchain/v6-c, 2026-09-06.
Source: LangChain changelog — langchain v1.2.0 · 2025-12-15 · langchain-core 1.6.1 published wheel — langchain_core/tools/base.py, the extras docstring example · 2026-08-27 · langchain-anthropic 1.7.1 published wheel -- chat_models.py, the whitelist that carries extras onto the wire · 2026-09-03 · langchain-core 1.1.3 published wheel -- the release below the window, where tools/base.py has no extras field · 2025-12-09
create_agent recursion limit
Behaviour changed in langchain 1.1.0 (2025-11-24)
Since 1.1.0, create_agent stamps its own recursion limit onto the graph it compiles, so an agent built by the factory does not run under LangGraph's default. 1.1.0 ended create_agent with .with_config({"recursion_limit": 10_000}); the shipped release sets {"recursion_limit": 9_999}. The number to know is that it is four figures, not 25. A GraphRecursionError from a factory-built agent therefore means thousands of supersteps have actually run — a genuine non-terminating loop — and raising the ceiling is not the fix.
The stale belief: That a create_agent agent inherits LangGraph's 25-superstep default (about twelve tool rounds), so a step-limit error is normal for a long tool loop and the fix is config={"recursion_limit": 100}.
# Stale
agent.invoke({"messages": [...]}, config={"recursion_limit": 100})
# Current
agent = create_agent(
model,
tools,
middleware=[ModelCallLimitMiddleware(run_limit=40, exit_behavior="end")],
)
Verified 2026-09-01 at both ends, from the shipped wheels; the changelog carries no line for it, so the introducing evidence is the 1.0.0/1.1.0 diff — 1.0.0 ends
create_agentwith a baregraph.compile(...). Deliberately scoped to the langchain side: LangGraph raised its ownDEFAULT_RECURSION_LIMITfrom 25 to 10000 at langgraph 1.1.0 (2026-03-10) and ships 10007 at langgraph 1.2.11, so "25" is now stale twice over — but the Index charges only thecreate_agentfact, which is inside every tested subject's window. The value moved between introduction and today (10,000 to 9,999), so the durable fact is the shape and the origin, not the integer.
Reproduced against: Claude Fable 5 (S2), Claude Opus 5 (S2), Claude Sonnet 5 (S2) — langchain/v3, 2026-09-01.
Source: langchain 1.0.0 published wheel — langchain/agents/factory.py (no limit set) · 2025-10-17 · langchain 1.1.0 published wheel — langchain/agents/factory.py (the change) · 2025-11-24 · langchain 1.3.18 published wheel — langchain/agents/factory.py (still true now, new value) · 2026-08-27
ModelRetryMiddleware defaults
Added in langchain 1.1.0 (2025-11-24)
ModelRetryMiddleware() with no arguments does not re-raise when its retries run out. Its defaults are max_retries=2 (three model calls in total) and on_failure="continue", and "continue" means the middleware swallows the provider exception and returns a ModelResponse carrying a synthetic AIMessage whose text is "Model call failed after N attempts with {ExcType}: {message}". The agent then proceeds as though the model had replied. Re-raising is opt-in: on_failure="error". Every parameter is keyword-only; the rest of the defaults are backoff_factor=2.0, initial_delay=1.0, max_delay=60.0, jitter=True (±25%).
The stale belief: That a bounded-retry middleware re-raises the underlying provider exception once attempts are exhausted, so agent.invoke(...) fails loudly when the provider is down.
# Stale
agent = create_agent(model, tools, middleware=[ModelRetryMiddleware()])
try:
result = agent.invoke({"messages": [...]})
except Exception:
alert_oncall() # never runs: nothing is raised
# Current
agent = create_agent(
model,
tools,
middleware=[ModelRetryMiddleware(on_failure="error")],
)
Verified 2026-09-01 at both ends. This is the sharpest failure mode in the 1.1.0 surface: a caller who believes the exception propagates writes an
exceptthat never fires and ships an agent that answers with an error string as if it were a model reply. One default did move after introduction and is recorded rather than smoothed over:retry_onwas(Exception,)at 1.1.0 and is thedefault_retry_oncallable in the shipped release, which honoursModelError.is_retryableand retries unclassified exceptions.max_retriesandon_failureare unchanged since 1.1.0.
Reproduced against: Claude Fable 5 (S2), Claude Opus 5 (S2), Claude Sonnet 5 (S2) — langchain/v3, 2026-09-01.
Source: LangChain changelog — langchain v1.1.0 · 2025-11-24 · langchain 1.3.18 published wheel — langchain/agents/middleware/model_retry.py · 2026-08-27
AgentMiddleware.modify_model_request
Removed in langchain 1.0.0 (2025-10-17)
modify_model_request is not a middleware hook in any released langchain 1.x. It existed in the 1.0 alpha line and was replaced before 1.0.0 GA by wrap_model_call(request, handler) — which receives the downstream handler and so can retry, short-circuit or post-process, none of which the old signature could do. The shipped hook set is before_agent / before_model / wrap_model_call / after_model / after_agent / wrap_tool_call, each with an a-prefixed async twin. Defining modify_model_request on an AgentMiddleware subclass raises nothing: the method is simply never called, and the middleware silently does nothing.
The stale belief: That middleware customises a model call by defining modify_model_request(self, request, state, runtime) and returning a modified request.
# Stale
class StampMiddleware(AgentMiddleware):
def modify_model_request(self, request, state, runtime) -> ModelRequest:
request.system_prompt = (request.system_prompt or "") + stamp
return request
# Current
class StampMiddleware(AgentMiddleware):
def wrap_model_call(self, request, handler):
base = request.system_message.text if request.system_message else ""
return handler(
request.override(system_message=SystemMessage(content=base + stamp))
)
Verified 2026-09-01. The string
modify_model_requestappears nowhere in the published 1.0.0, 1.1.0, 1.2.0 or 1.3.18 wheels — this is a fact established by its absence from the shipped artifact across the whole 1.x line, which is why the citation quotes the hook list that replaced it. Scored S2 rather than S1 because Python raises nothing: an unrecognised method on a subclass is legal, so the failure is a middleware that is registered, never fires, and is trusted anyway.
Reproduced against: Claude Sonnet 5 (S2) — langchain/v3, 2026-09-01.
Source: langchain 1.3.18 published wheel — langchain/agents/middleware/types.py (the shipped hook set) · 2026-08-27 · LangChain Python API reference — langchain.agents.middleware.AgentMiddleware
agent streaming node name
Renamed in langchain 1.0.0 (2025-10-17)
In a create_agent graph the model step is named "model", not "agent". Code that filters streamed events on "agent" imports, runs, and prints nothing — there is no error to tell you the filter never matched.
The stale belief: That the node emitting model output is called "agent", as it was in create_react_agent.
# Stale
for token, meta in agent.stream(inputs, stream_mode="messages"):
if meta.get("langgraph_node") == "agent": # never true
print(token.text, end="")
# Current
for token, meta in agent.stream(inputs, stream_mode="messages"):
if meta.get("langgraph_node") == "model":
print(token.text, end="")
This is the trap that survives a partial migration: swap
create_react_agentforcreate_agentand the streaming filter keeps compiling while silently going dark.
Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.
Source: LangChain v1 migration guide — Streaming node name rename
ChatAnthropic(max_tokens=...)
Default changed in langchain 1.0.0 (2025-10-17)
langchain-anthropic no longer defaults max_tokens to a flat 1024; it picks a higher value based on the model. Advice built on the old number — "your answer is being cut off at 1024 tokens" — describes a default that no longer exists. If you actually relied on 1024, set it explicitly.
The stale belief: That ChatAnthropic caps output at 1024 tokens unless you override it.
# Stale
model = ChatAnthropic(model="...") # believed: max_tokens defaults to 1024
# Current
model = ChatAnthropic(model="...", max_tokens=1024) # only if you want the old cap
Setting
max_tokensexplicitly remains good practice, so code written on the stale belief still runs correctly — it is the stated reason that is wrong.
Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.
Source: LangChain v1 migration guide — Default max_tokens in langchain-anthropic
ChatOpenAI Responses API output format
Default changed in langchain 1.0.0 (2025-10-17)
Against the OpenAI Responses API, langchain-openai now stores response items in message content by default. Code that parsed the previous shape keeps running and reads the wrong structure; restore the old behaviour with output_version="v0" or LC_OUTPUT_VERSION=v0.
The stale belief: That the Responses API output lands in the pre-1.0 content shape.
model = ChatOpenAI(model="...", output_version="v0") # opt back into the old shape
Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.
Source: LangChain v1 migration guide — Default message format for OpenAI responses API
Deprecated, or a better API now exists
Works today. It is the older idiom, and some of it is scheduled for removal.
astream_events(version="v3") on a create_agent agent
Added in langchain 1.3.0 (2026-05-12)
v2 is no longer the ceiling. From langchain 1.3.0 an agent built by create_agent accepts version="v3" in stream_events / astream_events - a content-block-centric protocol with typed, per-channel projections (run.values, run.messages, run.lifecycle, run.subgraphs), where run.messages yields one ChatModelStream per LLM call with sub-projections for text, reasoning, tool calls and usage. v1 and v2 are unchanged, so this is an addition rather than a migration. Scope matters: the claim is about the agent. The langchain package's own _ConfigurableModel.astream_events - what init_chat_model(..., configurable_fields=...) returns - still types version: Literal["v1", "v2"] = "v2" at 1.3.0 and 1.4.0.
The stale belief: That v2 is the highest event-stream protocol version that exists, v1 being the deprecated original - so a consumer that wants typed, per-channel event projections has to build them itself out of v2 events.
# Stale
async for event in agent.astream_events(inputs, version="v2"):
... # and reshape v2's flat event dicts by hand
# Current
async for event in agent.astream_events(inputs, version="v3"):
... # typed per-channel projections: run.values / run.messages /
# run.lifecycle / run.subgraphs
The changelog is the primary source for the langchain-side support and is quoted in full below; the artifact evidence is the dependency floor and the transformer registration that arrived with it (see LF37), plus langgraph 1.2.11, whose
pregel/main.pycarries the v3 machinery and rejects kwargs that would break v3's invariants. Verified 2026-09-06. Do not extend this fact to the configurable chat-model wrapper: that signature was checked at 1.3.0 and 1.4.0 and still stops at v2.
Reproduced against: Claude Fable 5.1 (S3) — langchain/v5-a, 2026-09-06.
Source: LangChain changelog - langchain v1.3.0, May 12, 2026 · 2026-05-12 · LangChain changelog - langgraph v1.2.0, the same day, on what v3 is · 2026-05-12 · langchain 1.3.0 published wheel - the langgraph>=1.2.0 floor and the ToolCallTransformer registration · 2026-05-12
create_agent(transformers=...)
Added in langchain 1.3.0 (2026-05-12)
create_agent takes a transformers= argument: a sequence of scope-aware StreamTransformer factories that are registered on the graph it compiles, in addition to the agent's own defaults. Each factory is invoked once per scope (factory(scope)), so a subgraph gets its own instance. The agent always registers ToolCallTransformer first and appends yours after it, so you keep the built-in behaviour instead of replacing it. This is the supported way to shape an agent's event stream at construction time: you do not have to abandon create_agent and hand-build the StateGraph, and you do not have to wrap .astream() on the consumer side.
The stale belief: That the compiled agent is a closed box: create_agent gives you no hook into the graph's stream machinery, so scope-aware transformation must be done either by dropping to a hand-built StateGraph or by wrapping .astream()/.astream_events() in your own generator and reconstructing scope from subgraphs=True namespace tuples.
# Stale
# stale: the capability is denied, so the requirement is met on the consumer side
agent = create_agent(model, tools, system_prompt="...")
async def my_stream(inputs, config=None):
per_scope = {}
async for ns, mode, chunk in agent.astream(
inputs, config=config, stream_mode=["updates"], subgraphs=True
):
per_scope.setdefault(ns, MyTransformer(ns))
yield per_scope[ns](mode, chunk)
# Current
agent = create_agent(
model,
tools,
system_prompt="...",
transformers=[MyTransformer], # factory, called once per scope
)
Verified against the shipped wheels on 2026-09-06. 1.2.18 has no
transformersparameter anywhere inlangchain/agents/factory.pyand callsgraph.compile()without one; 1.3.0 addstransformers: Sequence[Callable[[tuple[str, ...]], Any]] | None = Noneto the signature, importsToolCallTransformerfromlanggraph.prebuilt, and ends the compile call withtransformers=[ToolCallTransformer, *(transformers or ())]. 1.4.0 keeps it, retypes itSequence[TransformerFactory], and insertsAgentMiddleware.transformersbetween the built-in and yours. The dependency floor moves in the same release (langgraph<1.2.0,>=1.1.10at 1.2.18 ->langgraph<1.3.0,>=1.2.0at 1.3.0), because the transformer/mux machinery is langgraph 1.2.0's. Scored S3, not S1: the consumer-side wrapper the stale belief produces does run, so a denial costs a reader unnecessary code rather than a broken build.
Reproduced against: Claude Fable 5.1 (S3) — langchain/v5-a, 2026-09-06.
Source: langchain 1.3.0 published wheel - langchain/agents/factory.py · 2026-05-12 · langchain 1.2.18 published wheel - the release below the window, with no such parameter · 2026-05-08 · LangChain changelog - langchain v1.3.0 · 2026-05-12
ModelRequest.system_message
Renamed in langchain 1.1.0 (2025-11-24)
The system-instruction field on the ModelRequest object handed to middleware is system_message: SystemMessage | None. Until 1.1.0 it was system_prompt: str | None, a plain dataclass field. system_prompt survives as a read-only property returning self.system_message.text, and override(system_prompt=...) still converts, so pre-1.1 middleware keeps working — the shipped docstring labels the parameter "deprecated, converted to SystemMessage". Note the asymmetry that makes this easy to get wrong: create_agent itself still takes system_prompt=, so the public factory and the middleware-facing request now use different names for the same instruction.
The stale belief: That the middleware request carries the system instruction as a plain string field called system_prompt, the same name create_agent uses.
# Stale
def wrap_model_call(self, request, handler):
base = request.system_prompt or ""
return handler(request.override(system_prompt=base + stamp))
# Current
def wrap_model_call(self, request, handler):
base = request.system_message.text if request.system_message else ""
return handler(
request.override(system_message=SystemMessage(content=base + stamp))
)
Verified 2026-09-01 at both ends, from the shipped wheels rather than from release notes — the vendor changelog carries no line for this rename, so the introducing evidence is the 1.0.0/1.1.0 wheel diff, which is the artifact itself. Scored S3 rather than S2 because the old route genuinely still works; a reader following it gets a deprecation path, not a wrong result. The string route also loses what 1.1.0 added the object for: a
SystemMessagecan carry structured content blocks and provider cache markers that astrcannot.
Reproduced against: Claude Opus 5 (S3) — langchain/v3, 2026-09-01.
Source: langchain 1.0.0 published wheel — langchain/agents/middleware/types.py (the pre-rename state) · 2025-10-17 · langchain 1.1.0 published wheel — langchain/agents/middleware/types.py and agents/factory.py · 2025-11-24 · langchain 1.3.18 published wheel — langchain/agents/middleware/types.py (still true now) · 2026-08-27
langchain.agents.create_agent
Renamed in langchain 1.0.0 (2025-10-17)
create_agent from langchain.agents is the way to build an agent. langgraph.prebuilt.create_react_agent is deprecated as of LangGraph v1 in its favour; it still imports and runs, so this is not an immediate breakage, but every other v1 change below assumes you are on create_agent — the parameter names, the middleware hooks and the streaming node name all differ between the two.
The stale belief: That from langgraph.prebuilt import create_react_agent is the current recommended way to build a tool-calling agent, which it was throughout the 0.2/0.3 era.
# Stale
from langgraph.prebuilt import create_react_agent
agent = create_react_agent(model, tools, prompt="You are helpful.")
# Current
from langchain.agents import create_agent
agent = create_agent(model, tools, system_prompt="You are helpful.")
Two different functions have carried the name
create_react_agent: the LangGraph prebuilt (deprecated here) and the much olderlangchain.agents.react.agent.create_react_agent, which moved tolangchain-classic. Neither is the current answer.
Reproduced against: Claude Sonnet 5 (S3) — langchain/v1, 2026-08-31.
Source: LangGraph v1 migration guide — Deprecations · What's new in LangChain v1 — create_agent
model retry middleware
Added in langchain 1.1.0 (2025-11-24)
ModelRetryMiddleware ships in langchain.agents.middleware and retries the model call only, leaving tool calls alone. Its keyword-only parameters are max_retries, retry_on, on_failure, backoff_factor, initial_delay, max_delay and jitter. Do not hand-roll a wrap_model_call retry loop, and do not reach for the LCEL-era Runnable.with_retry() on the model — that predates this and wraps the model in a RunnableRetry before create_agent ever sees it.
The stale belief: That model-call retry has no first-class component, so it must be written as a custom wrap_model_call middleware, bolted on with .with_retry(), or wrapped in a try/except around the whole agent invocation.
# Stale
# stale: retries the entire graph, tool calls included -- not what was asked for
for attempt in range(5):
try:
result = agent.invoke(payload)
break
except (RateLimitError, APITimeoutError):
time.sleep(2**attempt)
# Current
from langchain.agents.middleware import ModelRetryMiddleware
agent = create_agent(
model=model,
tools=tools,
middleware=[
ModelRetryMiddleware(
max_retries=4,
retry_on=(RateLimitError, APITimeoutError),
backoff_factor=2.0,
initial_delay=1.0,
jitter=True,
)
],
)
Verified 2026-09-01 at both ends, with the parameter list read directly off the shipped
__init__. Whethercreate_agentactually rejects a.with_retry()-wrapped model is an open question in data/langchain/sonnet-5-v2.json and is deliberately not asserted here.
Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.
Source: LangChain changelog — langchain v1.1.0 · 2025-11-25 · langchain 1.3.18 published wheel — langchain/agents/middleware/model_retry.py · 2026-08-27
ModelRequest attribute assignment
Deprecated in langchain 1.1.0 (2025-11-24)
Assigning to any attribute of a ModelRequest in middleware is deprecated: 1.1.0 added a __setattr__ that emits a DeprecationWarning on every direct assignment and directs the caller to request.override(...), which returns a new request rather than mutating the shared one. override() itself is not new — it existed at 1.0.0 — but until 1.1.0 in-place mutation was an equally supported idiom, and LangChain's own ContextEditingMiddleware used it.
The stale belief: That middleware modifies the request in place — request.system_prompt = ..., request.messages.append(...) — and returns it.
# Stale
def wrap_model_call(self, request, handler):
request.system_prompt = request.system_prompt + stamp
return handler(request)
# Current
def wrap_model_call(self, request, handler):
return handler(request.override(system_message=SystemMessage(content=new_text)))
Verified 2026-09-01 at both ends, from the shipped wheels; the changelog carries no line for it. Corroborated inside the library's own source: at 1.0.0
context_editing.pymutatedrequest.messagesin place, and at 1.1.0 the same file deep-copies the list and returnshandler(request.override(messages=edited_messages)). Scored S3: the warning is a warning, the assignment still takes effect.
Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.
Source: langchain 1.0.0 published wheel — middleware/types.py defines no __setattr__; context_editing.py mutates in place · 2025-10-17 · langchain 1.3.18 published wheel — langchain/agents/middleware/types.py · 2026-08-27
SystemMessage as system_prompt
Added in langchain 1.1.0 (2025-11-24)
create_agent's system_prompt accepts a SystemMessage, not only a str. That is how a fixed instruction carries provider metadata — content blocks with cache_control for prompt caching, for instance — without adding middleware and without hand-assembling the message list. The shipped signature is system_prompt: str | SystemMessage | None.
The stale belief: That system_prompt is string-only, so any provider metadata on the system block requires middleware, a custom message list, or binding the hint on the model instead.
# Stale
# stale: assumes str-only, so the cache marker has nowhere to go
agent = create_agent(model=model, tools=tools, system_prompt=LONG_INSTRUCTIONS)
# Current
system = SystemMessage(
content=[
{
"type": "text",
"text": LONG_INSTRUCTIONS,
"cache_control": {"type": "ephemeral"},
}
]
)
agent = create_agent(model=model, tools=tools, system_prompt=system)
Verified 2026-09-01 at both ends. All three subjects tested on that date produced this form correctly, so it is carried as a correction for readers rather than as a measured model failure.
Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.
Source: LangChain changelog — langchain v1.1.0 · 2025-11-25 · langchain 1.3.18 published wheel — langchain/agents/factory.py · 2026-08-27
bind_tools return type
Behaviour changed in langchain 1.0.0 (2025-10-17)
Chat model invocation is typed as returning AIMessage, not BaseMessage. Custom chat models implementing bind_tools should narrow their return signature to match.
The stale belief: That bind_tools is annotated Runnable[LanguageModelInput, BaseMessage].
# Stale
def bind_tools(...) -> Runnable[LanguageModelInput, BaseMessage]:
# Current
def bind_tools(...) -> Runnable[LanguageModelInput, AIMessage]:
Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.
Source: LangChain v1 migration guide — Updated return type for chat models
built-in agent middleware
Added in langchain 1.0.0 (2025-10-17)
Middleware is the extension point of create_agent: hooks before_agent, before_model, wrap_model_call, wrap_tool_call, after_model, after_agent, plus built-ins including SummarizationMiddleware, HumanInTheLoopMiddleware, PIIMiddleware and TodoListMiddleware. Hand-rolled graph surgery for summarisation, approval gates or redaction is the pre-1.0 answer.
The stale belief: That customising the agent loop means writing your own LangGraph StateGraph.
The code below needs langchain 1.1.0 or later. Between 1.0.0 and 1.1.0 this correction does not apply — see the note.
from langchain.agents.middleware import SummarizationMiddleware, HumanInTheLoopMiddleware
agent = create_agent(model, tools, middleware=[
# on langchain 1.0.x this parameter is max_tokens_before_summary=500
SummarizationMiddleware(model=model, trigger={"tokens": 500}),
HumanInTheLoopMiddleware(interrupt_on={"send_email": {"allowed_decisions": ["approve", "reject"]}}),
])
CORRECTED 2026-09-02 (JOURNAL/037), by the first mechanical audit of a facts file (
tools/audit/). The middleware system does arrive at 1.0.0, and the fact is right about that — but the snippet above was written against the current release and does not run on any 1.0.x.SummarizationMiddlewaretookmax_tokens_before_summarythrough the whole 1.0 line and thetrigger=form did not exist until 1.1.0, wheremax_tokens_before_summarywas removed in the same release. Bisected in the installed packages: 1.0.0 and 1.0.8 acceptmax_tokens_before_summaryand rejecttrigger; 1.1.0, 1.2.0 and 1.3.18 accepttriggerand rejectmax_tokens_before_summary. So there is no single summarisation call that works across thelangchain>=1,<2range this pack claims, and a reader on 1.0.x copying the old text gotTypeError: unexpected keyword argument 'trigger'. On 1.0.x writeSummarizationMiddleware(model=model, max_tokens_before_summary=500)instead.triggertakes aTriggerClause— a total=False TypedDict with optionaltokens,messagesandfractionkeys — so the dict form above is the declared type and not merely an accepted one.HumanInTheLoopMiddleware(interrupt_on=...)was checked at both ends and is unchanged: it constructs identically on 1.0.8 and 1.3.18. 1.1.0 (2025-11-24) also added model-retry middleware; the Anthropic-specific middleware moved intolangchain-anthropicduring the 1.0 cycle.
Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.
Source: What's new in LangChain v1 — Middleware
message.content_blocks
Added in langchain 1.0.0 (2025-10-17)
Messages carry a provider-agnostic content_blocks property: typed blocks for text, reasoning, tool calls and citations that read the same across Anthropic, OpenAI, AWS, Google GenAI and Ollama. content is unchanged, so nothing breaks; per-provider branching on content is simply no longer necessary. Standard blocks are not serialised into content unless you opt in with output_version="v1" or LC_OUTPUT_VERSION=v1.
The stale belief: That normalising reasoning/text/tool-call output requires hand-written per-provider branches.
# Stale
for item in response.content:
if item.get("type") == "reasoning": ... # OpenAI
elif item.get("type") == "thinking": ... # Anthropic
# Current
for block in response.content_blocks:
if block["type"] == "reasoning": ...
elif block["type"] == "text": ...
Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.
Source: What's new in LangChain v1 — Standard content blocks
message.text
Deprecated in langchain 1.0.0 (2025-10-17)
.text is a property on message objects. The .text() method form still works but emits a warning and is scheduled for removal in v2.
The stale belief: That response.text() is the way to get a message's text.
# Stale
text = response.text()
# Current
text = response.text
Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.
Source: LangChain v1 migration guide — Text property
multimodal message input
Added in langchain 1.0.0 (2025-10-17)
Multimodal input has a standard form: HumanMessage(content_blocks=[{"type": "image", "url": ...}]). The provider-native {"type": "image_url", "image_url": {"url": ...}} shape inside content is the old spelling.
The stale belief: That images must be passed in each provider's own content shape.
# Stale
HumanMessage(content=[{"type": "image_url",
"image_url": {"url": "https://example.com/i.jpg"}}])
# Current
HumanMessage(content_blocks=[{"type": "image",
"url": "https://example.com/i.jpg"}])
Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.
Source: LangChain v1 migration guide — Create multimodal messages
run-scoped context (context= / context_schema=)
Added in langchain 1.0.0 (2025-10-17)
Static per-run data (a user id, a tenant) is passed with context= against a declared context_schema, and read inside a tool through a ToolRuntime parameter, which is stripped from the schema the model sees. The older config={"configurable": {...}} route still works and the migration guide says so explicitly — this is a better-idiom change, not a breakage.
The stale belief: That config["configurable"] is the only way to get request-scoped data into a tool.
# Stale
agent.invoke(state, config={"configurable": {"user_id": "u_1"}})
# Current
from dataclasses import dataclass
from langchain.tools import tool, ToolRuntime
@dataclass
class Context:
user_id: str
@tool
def get_orders(runtime: ToolRuntime[Context]) -> str:
"""Fetch the caller's orders."""
return lookup(runtime.context.user_id)
agent = create_agent(model, [get_orders], context_schema=Context)
agent.invoke(state, context=Context(user_id="u_1"))
Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.
Source: LangChain v1 migration guide — Runtime context · LangChain docs — Tools: ToolRuntime
Wrong facts about the library
Not code — versions, minimums and metadata that models state confidently and get wrong.
ProviderStrategy strict
Added in langchain 1.2.0 (2025-12-15)
ProviderStrategy takes a strict flag that asks the provider to enforce the schema server-side; when set, the strategy puts "strict": True into the JSON schema it sends. ProviderStrategy(Schema) alone is correct 1.0-era code and still routes to provider-native structured output — strict=True is the 1.2.0 addition on top of it.
The stale belief: That ProviderStrategy has no strictness control, so provider-side schema enforcement is all-or-nothing.
agent = create_agent(
model=model,
tools=tools,
response_format=ProviderStrategy(Verdict, strict=True),
)
Verified 2026-09-01 at both ends. Scored S4: omitting it is an incomplete answer rather than a wrong one, which is why the langchain/v2 battery treated it as supplementary and excluded it from its counts. All three subjects tested on that date produced
ProviderStrategy(Schema)without it.
Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.
Source: LangChain changelog — langchain v1.2.0 · 2025-12-15 · langchain 1.3.18 published wheel — langchain/agents/structured_output.py · 2026-08-27
model profiles (.profile)
Added in langchain 1.1.0 (2025-11-21)
Chat models carry a .profile attribute — a ModelProfile TypedDict describing what the model supports, loaded from the provider package. Ask the model object instead of keeping a table of model names: image_inputs, pdf_inputs, audio_inputs, max_input_tokens, structured_output and tool_calling are among its keys. It is total=False, so read every key with .get(). create_agent reads it internally to decide whether a model can do provider-native structured output.
The stale belief: That model capabilities must be hard-coded in a name-to-capability table, discovered by trial, or fetched from an external catalogue over HTTP.
# Stale
# stale: a table that goes out of date every time a provider ships a model
VISION = {"gpt-4o", "claude-sonnet-4-5", "gemini-2.5-pro"}
if model.model_name in VISION:
...
# Current
profile = getattr(model, "profile", None) or {}
if profile.get("image_inputs"):
... # send the image
else:
... # fall back to a text description
The introducing release is langchain-core 1.1.0 (2025-11-21), which is three days before langchain 1.1.0 (2025-11-24) — the changelog reports the feature under the langchain 1.1.0 heading. Re-verified 2026-09-01 against the shipped langchain-core 1.6.1 wheel, whose
profilefield docstring carries its ownversion-addedmarker naming 1.1.0. Measured on 2026-09-01: all three subjects tested (Opus 5, Fable 5, Sonnet 5) used.profilecorrectly and all three dated it to the 1.0 line. Key names sharpened 2026-09-01 from the shippedlangchain_core/language_models/model_profile.py:ModelProfileis atotal=FalseTypedDict, so every key may be absent and the docstring says to guard accesses with.get(). The input-capability keys areimage_inputs,image_url_inputs,pdf_inputs,audio_inputs,video_inputs— notsupports_visionor amodalitieslist.image_inputsandpdf_inputsare present from core 1.1.0;text_inputs,tool_call_streaming,attachmentandtemperaturewere added later.
Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.
Source: LangChain changelog — langchain v1.1.0 · 2025-11-25 · langchain-core 1.6.1 published wheel — langchain_core/language_models/chat_models.py · 2026-08-27 · langchain-core 1.6.1 published wheel — langchain_core/language_models/model_profile.py · 2026-08-27
langchain package namespace
Removed in langchain 1.0.0 (2025-10-17)
The v1 langchain package exports five modules and nothing else: langchain.agents, langchain.messages, langchain.tools, langchain.chat_models, langchain.embeddings. Most are re-exports from langchain-core. Describing langchain as a kitchen sink of chains, retrievers and integrations describes 0.3.
The stale belief: That langchain is a large package containing chains, retrievers, memory, the hub and integration code.
from langchain.agents import create_agent
from langchain.messages import AIMessage, HumanMessage
from langchain.tools import tool
from langchain.chat_models import init_chat_model
from langchain.embeddings import init_embeddings
Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.
Source: What's new in LangChain v1 — Namespace · API reference — the langchain package
langchain release timeline
New requirement in langchain 1.0.0 (2025-10-17)
langchain 1.0.0 was published to PyPI on 2025-10-17, together with langchain-core 1.0.0 and langchain-openai 1.0.0. 1.1.0 followed on 2025-11-24, 1.2.0 on 2025-12-15, 1.3.0 on 2026-05-12. The latest release as of 2026-08-31 is 1.3.18 (2026-08-27), with langchain-core at 1.6.1. The last 0.3 release before the 1.0 alpha line was 0.3.27 on 2025-07-24.
The stale belief: That 0.3.x is the current line, or that 1.0 is unreleased or upcoming.
Dates are the earliest file upload timestamp per release from the PyPI JSON API. The vendor changelog labels the 1.0.0 entry 'Oct 20, 2025'; the package files were uploaded 2025-10-17.
Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.
Source: PyPI JSON API — langchain release timestamps · LangChain Python changelog
Python version requirement
New requirement in langchain 1.0.0 (2025-10-17)
All LangChain packages require Python 3.10 or higher. Python 3.9 support was dropped in v1.
The stale belief: That LangChain still supports Python 3.9.
Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.
Source: LangChain v1 migration guide — Dropped Python 3.9 support
Not corrections — recorded for honesty
Claims seen in a run but not yet verified against a primary source. Never treated as findings:
- Are the beta identifier
advanced-tool-use-2025-11-20and the server-tool typetool_search_tool_regex_20251119, both volunteered by this draw, real Anthropic identifiers? (open since 2026-09-06) - Does
create_agentaccept a model that has been wrapped byRunnable.with_retry()? The shippedfactory.pytypes the parameterstr | BaseChatModeland only callsinit_chat_modelon the string branch, so aRunnableRetryis passed through un-validated to a code path that later reaches for chat-model methods. Relevant to Sonnet 5's P3 answer in the sibling run. (open since 2026-09-01) - This draw and
v1r-bwere given a byte-identical prompt, the same model alias, on the same day, running concurrently, and placed the boundary thirteen months apart (1.0.0 / 2025-10-17 here; 0.3.0 / 2024-09-13 there). Two draws establish that the instrument is not single-valued; they do not establish the shape of the distribution, which draw is modal, or whether the split is bimodal at all. (open since 2026-09-01) - Every other boundary published by the Index rests on a single draw of this same instrument, including the seven that produce Opus 5's three-day intersection. None has been replicated. (open since 2026-09-01)
- See
langchain--claude-sonnet-5--v1r-a--2026-09-01. This draw agrees withlangchain/v1; its twin does not, and both were given a byte-identical prompt on the same day. (open since 2026-09-01) - Task 10 did not reproduce v1's S2 stream-filter failure. One divergence in one task is not enough to say whether findings are as unstable as boundaries, and a code-level reproducibility check has never been run. (open since 2026-09-01)
- Does
create_agentaccept a model wrapped byRunnable.with_retry()? The shippedfactory.pytypes the parameterstr | BaseChatModeland only callsinit_chat_modelon the string branch, so aRunnableRetrypasses through un-validated into a path that later reaches for chat-model methods. If it raises, this subject's P3 is a build break rather than a partial. Not run, so not claimed. (open since 2026-09-01) - Sonnet 5's langchain boundary now has two measurements 13 months apart — 0.3.0 in v1 (2026-08-31) and a "1.0 alpha/beta, mid-2025" self-placement in v3 (2026-09-01). Is that elicitation variance from differently-shaped prompts, or is the v1 measurement wrong? Every published boundary in the Index rests on a single measurement per model per library, so this is a question about the instrument, not about this run. Re-run
langchain/v1against Sonnet 5 unchanged and compare before trusting either number. (open since 2026-09-01) - All three subjects named
max_retries=2correctly and all three asserted the exhausted-retry behaviour backwards. Is a default count systematically more guessable than a default policy? If so, future batteries should probe policies and treat counts as free. (open since 2026-09-01) - Does the deprecated
langgraph.prebuilt.create_react_agentstill acceptpre_model_hook=, and is its model node still named"agent", on current LangGraph? (open since 2026-08-31)
Findings, code and citations: data/langchain/ — one JSON file and one write-up per model, each finding carrying the release that broke the belief, its publication date and a verbatim quote from the primary source. Corrections: data/langchain/facts.json. This file is generated by tools/build-corrections.mjs; if the prose and the data ever disagree, that is a bug in the generator, not a stale pack.