LangChain ReAct agent — Could not parse LLM output
ReAct agents use text-based Thought/Action/Observation format. Modern models trained for tool calling deviate from this format regularly, producing parse errors that crash the agent.
Quick fix (TL;DR)
handle_parsing_errors=True or a custom parser callback, (b) migrating to create_tool_calling_agent where supported, and (c) tightening the prompt with explicit format examples.Real error messages you'll see
These are the exact strings returned by the LangChain framework and its integrations when this error occurs. Copy-paste-searching any of them should land on this page.
langchain.agents.output_parsers.react_single_input.ReActSingleInputOutputParser: Could not parse LLM output: `I need to search for information about the user's query. Let me use the search tool to find recent policy documents.` # The model wrote a thought but did not use the "Thought:" prefix
OutputParserException: Could not parse tool invocations. Multiple Action blocks found in one response.
OutputParserException: Could not parse LLM output: ```json
{"action": "search", "action_input": "..."}
```
# Model produced JSON in a code fence; parser wanted plain "Action: search" text
Reference
When to use ReAct vs tool_calling agents
| Situation | Recommendation |
|---|---|
| Provider supports tool calling (OpenAI, Anthropic, Google, Bedrock) | create_tool_calling_agent |
| Provider is a base model without tool calling (Ollama, local) | create_react_agent |
| Legacy code with ReAct working today | Keep with handle_parsing_errors |
| New agent workflow | create_tool_calling_agent |
| Complex reasoning steps that benefit from visible thoughts | Either — but tool calling with thinking blocks (Claude 4+) is better |
Root causes, ranked by frequency
Based on developer reports across LangChain forums, GitHub issues, and Discord community during 2025–2026.
- 28%Model deviates from ReAct format. Modern models fluent in tool calling forget the ReAct text format.
- 18%Markdown or code blocks in output. Model formats tool calls as JSON code fences instead of plain text.
- 14%Multiple actions in one response. Newer models attempt parallel tool calls even in ReAct.
- 10%Missing example in prompt. Without a clear example, models improvise on the format.
- 8%Non-ASCII / unicode in tool names. Regex-based parser mis-matches.
- 7%Tool name with underscores or hyphens. Parser expects specific patterns.
- 7%Thought/observation contain "Action:" as normal text. Parser sees a false action marker.
- 8%Truncation mid-response. Model output cut off mid-format; parser fails on partial.
Fixes — copy-paste solutions
Enable handle_parsing_errors to convert crashes into retries
Set handle_parsing_errors=True on the executor. When parsing fails, the executor feeds the raw output back to the model as an "observation" and asks it to try again in the correct format.
from langchain.agents import AgentExecutor, create_react_agent from langchain_openai import ChatOpenAI from langchain_core.prompts import PromptTemplate from langchain import hub llm = ChatOpenAI(model="gpt-4o-mini", temperature=0) # Load the standard ReAct prompt prompt = hub.pull("hwchase17/react") # Or write your own with explicit examples custom_prompt = PromptTemplate.from_template(""" Answer the following question using the tools available. TOOLS: {tools} Follow this EXACT format: Thought: your reasoning about what to do Action: the tool name (one of [{tool_names}]) Action Input: the input to the tool Observation: the tool result (system will fill in) ... (repeat Thought/Action/Action Input/Observation as needed) Thought: I now know the final answer Final Answer: your final answer to the user Question: {input} {agent_scratchpad} """) agent = create_react_agent(llm, tools, custom_prompt) executor = AgentExecutor( agent=agent, tools=tools, verbose=True, max_iterations=8, handle_parsing_errors=True, # ← retry on parse failure # Alternative: pass a callable # handle_parsing_errors=lambda e: f"Parsing error: {e}. Please respond in the exact ReAct format.", early_stopping_method="generate", ) result = executor.invoke({"input": "What is the weather in Karachi?"})
handle_parsing_errors=True, repeated parse failures burn tokens. Track parse-error rate in production and consider migrating to tool-calling agents if it exceeds 5-10%.Migrate to create_tool_calling_agent when the provider supports it
Tool-calling agents use provider-native structured tool calls. No text-parsing brittleness. Every major provider (OpenAI, Anthropic, Google, most on Bedrock) supports it.
# BEFORE — fragile ReAct agent # from langchain.agents import create_react_agent, AgentExecutor # from langchain import hub # prompt = hub.pull("hwchase17/react") # agent = create_react_agent(llm, tools, prompt) # executor = AgentExecutor(agent=agent, tools=tools, handle_parsing_errors=True) # AFTER — robust tool-calling agent from langchain.agents import create_tool_calling_agent, AgentExecutor from langchain_core.prompts import ChatPromptTemplate from langchain_openai import ChatOpenAI llm = ChatOpenAI(model="gpt-4o-mini") # The tool-calling agent prompt is simpler — no format-enforcement bloat prompt = ChatPromptTemplate.from_messages([ ("system", "You are helpful. Use tools when they help. " "When you have enough information, produce the final answer."), ("human", "{input}"), ("placeholder", "{agent_scratchpad}"), ]) agent = create_tool_calling_agent(llm, tools, prompt) executor = AgentExecutor( agent=agent, tools=tools, verbose=True, max_iterations=8, max_execution_time=60, early_stopping_method="generate", # handle_parsing_errors is unnecessary — tool calls are structured ) result = executor.invoke({"input": "What is the weather in Karachi?"}) print(result["output"]) # Tool-calling agents also support parallel tool calls when the provider does llm_parallel = ChatOpenAI(model="gpt-4o-mini") agent_parallel = create_tool_calling_agent(llm_parallel, tools, prompt) executor_parallel = AgentExecutor(agent=agent_parallel, tools=tools, ...)
Use a custom output parser for edge-case ReAct scenarios
Subclass or wrap ReActSingleInputOutputParser to handle common deviations (markdown fences, extra whitespace, missing "Thought:" prefix).
import re from langchain.agents.output_parsers.react_single_input import ReActSingleInputOutputParser from langchain_core.agents import AgentAction, AgentFinish from langchain_core.exceptions import OutputParserException class LenientReActParser(ReActSingleInputOutputParser): """Handles common ReAct format deviations before the strict parser.""" def parse(self, text: str): # Strip markdown code fences that some models emit cleaned = re.sub(r"```(?:json|python)?\n?(.+?)\n?```", r"\1", text, flags=re.DOTALL) # Sometimes models emit "Thought" without colon — add it cleaned = re.sub(r"^Thought(?!:)", "Thought:", cleaned, flags=re.MULTILINE) # Sometimes models write "Answer:" instead of "Final Answer:" cleaned = re.sub(r"^Answer:", "Final Answer:", cleaned, flags=re.MULTILINE) try: return super().parse(cleaned) except OutputParserException: # Fallback: if the text ends without an Action, treat it as final answer if "Action:" not in cleaned: return AgentFinish( return_values={"output": cleaned.strip()}, log=text, ) raise # re-raise so handle_parsing_errors kicks in # Use it with the executor from langchain.agents import create_react_agent agent = create_react_agent(llm, tools, prompt, output_parser=LenientReActParser())
Prevention checklist
Ship these seven safeguards once and this error stops appearing in your logs.
- Prefer
create_tool_calling_agentovercreate_react_agentfor any provider that supports tool calling. - When forced to use ReAct, set
handle_parsing_errors=Trueon every executor. - Include an explicit format example in the ReAct prompt — do not rely on training alone.
- Set
temperature=0for ReAct agents to reduce format deviation. - Monitor parse error rates in production; migrate when they exceed 5%.
- For local / open-source models, budget for a custom parser — ReAct is more fragile there.
- Never mix ReAct format with tool_calling output on the same model instance.
Frequently asked questions
create_tool_calling_agent with Claude — it works out of the box and eliminates parse errors entirely.initialize_agent is deprecated. Use create_tool_calling_agent for provider-native tool calling, or create_react_agent for text-based ReAct. Both are used with AgentExecutor.AgentExecutor is fine. For state machines, multi-agent orchestration, or explicit control flow, LangGraph is much better.Related errors & hubs
Get the weekly AI-error digest
New fixes, provider status recaps, and one deep tutorial — every Tuesday. 8,400+ engineers.