-
Notifications
You must be signed in to change notification settings - Fork 19.9k
Description
Checked other resources
- This is a bug, not a usage question. For questions, please use GitHub Discussions.
- I added a clear and detailed title that summarizes the issue.
- I read what a minimal reproducible example is (https://stackoverflow.com/help/minimal-reproducible-example).
- I included a self-contained, minimal example that demonstrates the issue INCLUDING all the relevant imports. The code run AS IS to reproduce the issue.
Example Code
"""
Minimal reproduction case for LangGraph InjectedState bug.
ISSUE: InjectedState and InjectedToolCallId parameters must be explicitly
included in the tool's args_schema for injection to work, even though they
should be automatically excluded from the LLM schema.
EXPECTED BEHAVIOR:
- InjectedState and InjectedToolCallId should work without being in args_schema
- These parameters should be automatically injected by LangGraph
- The LLM should never see these parameters in the tool schema
ACTUAL BEHAVIOR:
- InjectedState and InjectedToolCallId must be included in args_schema
- Without them in args_schema, injection fails with missing parameter error
"""
from typing import Annotated, List
from pydantic import BaseModel, Field
from langgraph.graph import StateGraph, add_messages
from langgraph.constants import START, END
from langgraph.prebuilt import ToolNode, InjectedState
from langchain_core.tools import tool, InjectedToolCallId
from langchain_core.messages import BaseMessage, AIMessage
from langgraph.checkpoint.memory import MemorySaver
class SimpleState(BaseModel):
messages: Annotated[List[BaseMessage], add_messages] = Field(default_factory=list)
counter: int = 0
class CorrectToolSchema(BaseModel):
"""This should work but doesn't - injection fails."""
text: str = Field(description="Text to process")
# InjectedState and InjectedToolCallId should NOT need to be here
@tool(
"broken_tool",
description="Tool that should work with automatic injection",
args_schema=CorrectToolSchema,
)
def broken_tool(
text: str,
state: Annotated[SimpleState, InjectedState],
tool_call_id: Annotated[str, InjectedToolCallId],
) -> str:
"""This tool fails because injected params aren't in args_schema."""
return f"Processed '{text}' (counter: {state.counter})"
class WorkaroundToolSchema(BaseModel):
"""Workaround: explicitly include injected params in schema."""
text: str = Field(description="Text to process")
# BUG: These shouldn't be needed but are required for injection to work
state: Annotated[SimpleState, InjectedState]
tool_call_id: Annotated[str, InjectedToolCallId]
@tool(
"working_tool",
description="Tool that works only because of explicit schema inclusion",
args_schema=WorkaroundToolSchema,
)
def working_tool(
text: str,
state: Annotated[SimpleState, InjectedState],
tool_call_id: Annotated[str, InjectedToolCallId],
) -> str:
"""This tool works but requires injected params in args_schema."""
return f"Processed '{text}' (counter: {state.counter})"
def test_broken_injection():
"""Test the broken tool to demonstrate the issue."""
print("🔴 TESTING BROKEN TOOL (Expected behavior that doesn't work)")
print("=" * 70)
workflow = StateGraph(SimpleState)
workflow.add_node(
"test",
lambda state: {
"messages": [
AIMessage(
content="Using broken tool",
tool_calls=[
{"id": "test_123", "name": "broken_tool", "args": {"text": "test data"}}
],
)
]
},
)
workflow.add_node("tools", ToolNode([broken_tool]))
workflow.add_edge(START, "test")
workflow.add_edge("test", "tools")
workflow.add_edge("tools", END)
graph = workflow.compile(checkpointer=MemorySaver())
result = graph.invoke({"counter": 10}, {"configurable": {"thread_id": "test"}})
print(f"❌ Broken tool result:\n{result}")
def test_working_injection():
"""Test the working tool to show the workaround."""
print("\n🟢 TESTING WORKING TOOL (Workaround that shouldn't be necessary)")
print("=" * 70)
workflow = StateGraph(SimpleState)
workflow.add_node(
"test",
lambda state: {
"messages": [
AIMessage(
content="Using working tool",
tool_calls=[
{
"id": "test_456",
"name": "working_tool",
"args": {"text": "test data"},
}
],
)
]
},
)
workflow.add_node("tools", ToolNode([working_tool]))
workflow.add_edge(START, "test")
workflow.add_edge("test", "tools")
workflow.add_edge("tools", END)
graph = workflow.compile(checkpointer=MemorySaver())
result = graph.invoke({"counter": 10}, {"configurable": {"thread_id": "test"}})
print(f"✅ Working tool result:\n{result}")
if __name__ == "__main__":
test_broken_injection()
test_working_injection()Error Message and Stack Trace (if applicable)
🔴 TESTING BROKEN TOOL (Expected behavior that doesn't work)
======================================================================
❌ Broken tool result:
{'messages': [AIMessage(content='Using broken tool', additional_kwargs={}, response_metadata={}, id='011abcbf-f246-47f1-9b18-b0620412221d', tool_calls=[{'name': 'broken_tool', 'args': {'text': 'test data'}, 'id': 'test_123', 'type': 'tool_call'}]), ToolMessage(content='Error: TypeError("broken_tool() missing 2 required positional arguments: \'state\' and \'tool_call_id\'")\n Please fix your mistakes.', name='broken_tool', id='4b4a067a-c13e-4437-b929-0210379403a7', tool_call_id='test_123', status='error')], 'counter': 10}
🟢 TESTING WORKING TOOL (Workaround that shouldn't be necessary)
======================================================================
✅ Working tool result:
{'messages': [AIMessage(content='Using working tool', additional_kwargs={}, response_metadata={}, id='e988d222-eadd-443e-9869-41fadfaea54e', tool_calls=[{'name': 'working_tool', 'args': {'text': 'test data'}, 'id': 'test_456', 'type': 'tool_call'}]), ToolMessage(content="Processed 'test data' (counter: 10)", name='working_tool', id='a99fa4b6-1c0d-4319-be75-de82f38762b3', tool_call_id='test_456')], 'counter': 10}Description
When tool is created using the @tool decorated and input schema is provided, the state is not being injected into the tool.
The state needs to be added as part of the input schema, which does not makes sense, as the idea of the input schema is to provide the LLM with context on the inputs to the tools and adding the state and other injectable data into input schema does not look good and causes confusion.
System Info
System Information
OS: Linux
OS Version: langchain-ai/langgraph#1 SMP PREEMPT_DYNAMIC Mon Apr 21 17:08:54 UTC 2025
Python Version: 3.12.10 (main, Apr 29 2025, 00:24:54) [GCC 12.2.0]
Package Information
langchain_core: 0.3.63
langchain: 0.3.25
langchain_community: 0.3.24
langsmith: 0.3.44
langchain_openai: 0.2.14
langchain_text_splitters: 0.3.8
langgraph_injection_bug: Installed. No version info available.
langgraph_sdk: 0.1.70
Optional packages not installed
langserve
Other Dependencies
aiohttp<4.0.0,>=3.8.3: Installed. No version info available.
async-timeout<5.0.0,>=4.0.0;: Installed. No version info available.
dataclasses-json<0.7,>=0.5.7: Installed. No version info available.
httpx: 0.28.1
httpx-sse<1.0.0,>=0.4.0: Installed. No version info available.
httpx>=0.25.2: Installed. No version info available.
jsonpatch<2.0,>=1.33: Installed. No version info available.
langchain-anthropic;: Installed. No version info available.
langchain-aws;: Installed. No version info available.
langchain-azure-ai;: Installed. No version info available.
langchain-cohere;: Installed. No version info available.
langchain-community;: Installed. No version info available.
langchain-core<1.0.0,>=0.3.51: Installed. No version info available.
langchain-core<1.0.0,>=0.3.58: Installed. No version info available.
langchain-core<1.0.0,>=0.3.59: Installed. No version info available.
langchain-deepseek;: Installed. No version info available.
langchain-fireworks;: Installed. No version info available.
langchain-google-genai;: Installed. No version info available.
langchain-google-vertexai;: Installed. No version info available.
langchain-groq;: Installed. No version info available.
langchain-huggingface;: Installed. No version info available.
langchain-mistralai;: Installed. No version info available.
langchain-ollama;: Installed. No version info available.
langchain-openai;: Installed. No version info available.
langchain-perplexity;: Installed. No version info available.
langchain-text-splitters<1.0.0,>=0.3.8: Installed. No version info available.
langchain-together;: Installed. No version info available.
langchain-xai;: Installed. No version info available.
langchain<1.0.0,>=0.3.25: Installed. No version info available.
langsmith-pyo3: Installed. No version info available.
langsmith<0.4,>=0.1.125: Installed. No version info available.
langsmith<0.4,>=0.1.126: Installed. No version info available.
langsmith<0.4,>=0.1.17: Installed. No version info available.
numpy>=1.26.2;: Installed. No version info available.
numpy>=2.1.0;: Installed. No version info available.
openai: 1.83.0
openai-agents: Installed. No version info available.
opentelemetry-api: 1.28.2
opentelemetry-exporter-otlp-proto-http: Installed. No version info available.
opentelemetry-sdk: 1.28.2
orjson: 3.10.18
orjson>=3.10.1: Installed. No version info available.
packaging: 24.2
packaging<25,>=23.2: Installed. No version info available.
pydantic: 2.11.5
pydantic-settings<3.0.0,>=2.4.0: Installed. No version info available.
pydantic<3.0.0,>=2.7.4: Installed. No version info available.
pydantic>=2.7.4: Installed. No version info available.
pytest: 8.4.0
PyYAML>=5.3: Installed. No version info available.
requests: 2.32.3
requests-toolbelt: 1.0.0
requests<3,>=2: Installed. No version info available.
rich: Installed. No version info available.
SQLAlchemy<3,>=1.4: Installed. No version info available.
tenacity!=8.4.0,<10,>=8.1.0: Installed. No version info available.
tenacity!=8.4.0,<10.0.0,>=8.1.0: Installed. No version info available.
tiktoken: 0.9.0
typing-extensions>=4.7: Installed. No version info available.
zstandard: 0.23.0