[Bug] InjectedState not passed to tools when using create_agent() — causes “state: Field required” error in LangGraph multi-agent setup #1025

Closed
opened 2026-02-20 17:42:47 -05:00 by yindo · 0 comments
Owner

Originally created by @ayylemao on GitHub (Oct 27, 2025).

Checked other resources

  • This is a bug, not a usage question. For questions, please use the LangChain Forum (https://forum.langchain.com/).
  • 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

import asyncio
import os
from typing import Annotated, List
from langchain.agents import create_agent
from langchain_core.tools import tool, InjectedToolCallId
from langgraph.graph import MessagesState, StateGraph, START, END
from langgraph.types import Command
from langgraph.prebuilt import InjectedState
from langchain_groq import ChatGroq


os.environ["GROQ_API_KEY"] = #API KEY
# I also tested with anthropic as llm provider for same results


def _create_handoff_tool(*, target_agent: str):
    """
    Tool to transfer control to another agent (subgraph) using InjectedState.
    """
    name = f"transfer_to_{target_agent}"
    description = f"Transfer control to {target_agent}."

    @tool(name, description=description)
    def handoff_tool(
        state: Annotated[MessagesState, InjectedState],
        tool_call_id: Annotated[str, InjectedToolCallId]
    ) -> Command:
        tool_message = {
            "role": "tool",
            "name": name,
            "content": f"Successfully transferred control to {target_agent}.",
            "tool_call_id": tool_call_id,
        }

        # attempt to merge state into parent graph
        return Command(
            goto=target_agent,
            update={"messages": state["messages"] + [tool_message]},
            graph=Command.PARENT,
        )

    return handoff_tool


def make_agent(name: str, prompt: str, transitions: List[str] | None = None):
    transitions = transitions or []
    tools = [_create_handoff_tool(target_agent=t) for t in transitions]
    model = ChatGroq(model="llama-3.3-70b-versatile", temperature=0)
    return create_agent(model=model, tools=tools, system_prompt=prompt, name=name)


async def main():
    agent_a = make_agent(
        "agent_a",
        "You are agent A. You analyze input and then transfer control to agent B.",
        transitions=["agent_b"],
    )

    agent_b = make_agent(
        "agent_b",
        "You are agent B. You summarize what agent A has done.",
    )

    graph = (
        StateGraph(MessagesState)
        .add_node("agent_a", agent_a)
        .add_node("agent_b", agent_b)
        .add_edge(START, "agent_a")
        .add_edge("agent_a", "agent_b")
        .add_edge("agent_b", END)
        .compile()
    )

    # Initial message
    state = {"messages": [{"role": "user", "content": "Start analysis."}]}

    async for chunk in graph.astream(state, subgraphs=True, stream_mode="messages"):
        print(chunk)
        print("\n")


if __name__ == "__main__":
    asyncio.run(main())

Error Message and Stack Trace (if applicable)

(('agent_a:972853e0-7e0c-6d75-e432-2eccdf835512',), (AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'x26yjdr7k', 'function': {'arguments': 'null', 'name': 'transfer_to_agent_b'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 11, 'prompt_tokens': 224, 'total_tokens': 235, 'completion_time': 0.017884536, 'prompt_time': 0.021215799, 'queue_time': 0.163930933, 'total_time': 0.039100335}, 'model_name': 'llama-3.3-70b-versatile', 'system_fingerprint': 'fp_55062f05af', 'service_tier': 'on_demand', 'finish_reason': 'tool_calls', 'logprobs': None, 'model_provider': 'groq'}, id='lc_run--7ba018bc-b8fe-49bd-b114-08cd5033a707-0', tool_calls=[{'name': 'transfer_to_agent_b', 'args': {}, 'id': 'x26yjdr7k', 'type': 'tool_call'}], usage_metadata={'input_tokens': 224, 'output_tokens': 11, 'total_tokens': 235}), {'langgraph_step': 1, 'langgraph_node': 'model', 'langgraph_triggers': ('branch:to:model',), 'langgraph_path': ('__pregel_pull', 'model'), 'langgraph_checkpoint_ns': 'agent_a:972853e0-7e0c-6d75-e432-2eccdf835512|model:06e18167-76d6-f5e7-8252-025da5bedc28', 'checkpoint_ns': 'agent_a:972853e0-7e0c-6d75-e432-2eccdf835512'}))


(('agent_a:972853e0-7e0c-6d75-e432-2eccdf835512',), (ToolMessage(content="Error invoking tool 'transfer_to_agent_b' with kwargs {} with error:\n state: Field required\n Please fix the error and try again.", name='transfer_to_agent_b', id='5059e6b8-34fb-402e-820d-a7ca8450274c', tool_call_id='x26yjdr7k', status='error'), {'langgraph_step': 2, 'langgraph_node': 'tools', 'langgraph_triggers': ('__pregel_push',), 'langgraph_path': ('__pregel_push', 0, False), 'langgraph_checkpoint_ns': 'agent_a:972853e0-7e0c-6d75-e432-2eccdf835512|tools:1d202cd5-67dc-81c5-d243-8f3440135a0c', 'checkpoint_ns': 'agent_a:972853e0-7e0c-6d75-e432-2eccdf835512'}))

Description

When defining a handoff tool that should transfer control between subgraphs (multi-agent setup), using InjectedState as a tool argument causes LangGraph to fail during runtime with a validation error:

Error invoking tool 'transfer_to_example_agent_b' with kwargs {} with error:
 state: Field required
 Please fix the error and try again.

I am creating a multi-agent LangGraph pipeline using StateGraph and create_agent from LangChain. Each sub-agent has its own tools plus a dynamically created “handoff” tool that returns a Command to transfer control to another subgraph.

The tool is defined as follows:

@tool(name, description=description)
def handoff_tool(
    tool_call_id: Annotated[str, InjectedToolCallId],
    state: Annotated[MessagesState, InjectedState],
) -> Command:
    tool_message = {
        "role": "tool",
        "name": name,
        "content": f"Successfully transferred control to {target_agent}.",
        "tool_call_id": tool_call_id,
    }

    return Command(
        goto=target_agent,
        update={"message": state["messages"] + [tool_message]},
        graph=Command.PARENT,
    )

When this tool is called by the model, LangGraph raises the above error instead of injecting the current state.
It seems that InjectedState is not being passed to tools created via LangChain’s @tool decorator or create_agent() API.


Expected Behavior

  • The tool should receive the active MessagesState via the InjectedState parameter.
  • The tool should be able to return a Command that includes state["messages"] for merging into the parent graph as seen in one of the examples here https://langchain-ai.github.io/langgraph/agents/multi-agent/#handoffs
  • The state should persist across subgraph boundaries (i.e., the next agent should see the full conversation so far).

Actual Behavior

  • The model calls the tool with {} (no arguments).
  • LangGraph raises an error saying state: Field required.
  • The handoff fails, and the next subgraph never receives previous context.

Environment

Dependencies:

dependencies = [
    "langchain>=1.0.2",
    "langchain-groq>=1.0.0",
    "langchain-mcp-adapters>=0.1.11",
    "langgraph>=1.0.1",
    "langsmith>=0.4.37",
]

Additional Context

The example shown on the langgraph/agents/multi-agent documentation is still using the deprecated create_react_agent. The migration guide however does not mention anything that should change besides the import and function name.
If this is intended, there should be documentation clarifying that InjectedState is not supported for tools passed through LangChain’s agent wrappers.

System Info

System Information

OS: Linux
OS Version: #1 SMP PREEMPT_DYNAMIC Thu Jun 5 18:30:46 UTC 2025
Python Version: 3.10.12 (main, Aug 15 2025, 14:32:43) [GCC 11.4.0]

Package Information

langchain_core: 1.0.0
langchain: 1.0.2
langsmith: 0.4.37
langchain_groq: 1.0.0
langchain_mcp_adapters: 0.1.11
langgraph_sdk: 0.2.9

Optional packages not installed

langserve

Other Dependencies

claude-agent-sdk: Installed. No version info available.
groq: 0.33.0
httpx: 0.28.1
jsonpatch: 1.33
langchain-anthropic: Installed. No version info available.
langchain-aws: Installed. No version info available.
langchain-community: 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-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-together: Installed. No version info available.
langchain-xai: Installed. No version info available.
langgraph: 1.0.1
langsmith-pyo3: Installed. No version info available.
mcp: 1.18.0
openai-agents: Installed. No version info available.
opentelemetry-api: Installed. No version info available.
opentelemetry-exporter-otlp-proto-http: Installed. No version info available.
opentelemetry-sdk: Installed. No version info available.
orjson: 3.11.3
packaging: 25.0
pydantic: 2.12.3
pytest: Installed. No version info available.
pyyaml: 6.0.3
requests: 2.32.5
requests-toolbelt: 1.0.0
rich: Installed. No version info available.
tenacity: 9.1.2
typing-extensions: 4.15.0
vcrpy: Installed. No version info available.
zstandard: 0.25.0

Originally created by @ayylemao on GitHub (Oct 27, 2025). ### Checked other resources - [x] This is a bug, not a usage question. For questions, please use the LangChain Forum (https://forum.langchain.com/). - [x] I added a clear and detailed title that summarizes the issue. - [x] I read what a minimal reproducible example is (https://stackoverflow.com/help/minimal-reproducible-example). - [x] 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 ```python import asyncio import os from typing import Annotated, List from langchain.agents import create_agent from langchain_core.tools import tool, InjectedToolCallId from langgraph.graph import MessagesState, StateGraph, START, END from langgraph.types import Command from langgraph.prebuilt import InjectedState from langchain_groq import ChatGroq os.environ["GROQ_API_KEY"] = #API KEY # I also tested with anthropic as llm provider for same results def _create_handoff_tool(*, target_agent: str): """ Tool to transfer control to another agent (subgraph) using InjectedState. """ name = f"transfer_to_{target_agent}" description = f"Transfer control to {target_agent}." @tool(name, description=description) def handoff_tool( state: Annotated[MessagesState, InjectedState], tool_call_id: Annotated[str, InjectedToolCallId] ) -> Command: tool_message = { "role": "tool", "name": name, "content": f"Successfully transferred control to {target_agent}.", "tool_call_id": tool_call_id, } # attempt to merge state into parent graph return Command( goto=target_agent, update={"messages": state["messages"] + [tool_message]}, graph=Command.PARENT, ) return handoff_tool def make_agent(name: str, prompt: str, transitions: List[str] | None = None): transitions = transitions or [] tools = [_create_handoff_tool(target_agent=t) for t in transitions] model = ChatGroq(model="llama-3.3-70b-versatile", temperature=0) return create_agent(model=model, tools=tools, system_prompt=prompt, name=name) async def main(): agent_a = make_agent( "agent_a", "You are agent A. You analyze input and then transfer control to agent B.", transitions=["agent_b"], ) agent_b = make_agent( "agent_b", "You are agent B. You summarize what agent A has done.", ) graph = ( StateGraph(MessagesState) .add_node("agent_a", agent_a) .add_node("agent_b", agent_b) .add_edge(START, "agent_a") .add_edge("agent_a", "agent_b") .add_edge("agent_b", END) .compile() ) # Initial message state = {"messages": [{"role": "user", "content": "Start analysis."}]} async for chunk in graph.astream(state, subgraphs=True, stream_mode="messages"): print(chunk) print("\n") if __name__ == "__main__": asyncio.run(main()) ``` ### Error Message and Stack Trace (if applicable) ```shell (('agent_a:972853e0-7e0c-6d75-e432-2eccdf835512',), (AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'x26yjdr7k', 'function': {'arguments': 'null', 'name': 'transfer_to_agent_b'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 11, 'prompt_tokens': 224, 'total_tokens': 235, 'completion_time': 0.017884536, 'prompt_time': 0.021215799, 'queue_time': 0.163930933, 'total_time': 0.039100335}, 'model_name': 'llama-3.3-70b-versatile', 'system_fingerprint': 'fp_55062f05af', 'service_tier': 'on_demand', 'finish_reason': 'tool_calls', 'logprobs': None, 'model_provider': 'groq'}, id='lc_run--7ba018bc-b8fe-49bd-b114-08cd5033a707-0', tool_calls=[{'name': 'transfer_to_agent_b', 'args': {}, 'id': 'x26yjdr7k', 'type': 'tool_call'}], usage_metadata={'input_tokens': 224, 'output_tokens': 11, 'total_tokens': 235}), {'langgraph_step': 1, 'langgraph_node': 'model', 'langgraph_triggers': ('branch:to:model',), 'langgraph_path': ('__pregel_pull', 'model'), 'langgraph_checkpoint_ns': 'agent_a:972853e0-7e0c-6d75-e432-2eccdf835512|model:06e18167-76d6-f5e7-8252-025da5bedc28', 'checkpoint_ns': 'agent_a:972853e0-7e0c-6d75-e432-2eccdf835512'})) (('agent_a:972853e0-7e0c-6d75-e432-2eccdf835512',), (ToolMessage(content="Error invoking tool 'transfer_to_agent_b' with kwargs {} with error:\n state: Field required\n Please fix the error and try again.", name='transfer_to_agent_b', id='5059e6b8-34fb-402e-820d-a7ca8450274c', tool_call_id='x26yjdr7k', status='error'), {'langgraph_step': 2, 'langgraph_node': 'tools', 'langgraph_triggers': ('__pregel_push',), 'langgraph_path': ('__pregel_push', 0, False), 'langgraph_checkpoint_ns': 'agent_a:972853e0-7e0c-6d75-e432-2eccdf835512|tools:1d202cd5-67dc-81c5-d243-8f3440135a0c', 'checkpoint_ns': 'agent_a:972853e0-7e0c-6d75-e432-2eccdf835512'})) ``` ### Description When defining a handoff tool that should transfer control between subgraphs (multi-agent setup), using `InjectedState` as a tool argument causes LangGraph to fail during runtime with a validation error: ``` Error invoking tool 'transfer_to_example_agent_b' with kwargs {} with error: state: Field required Please fix the error and try again. ``` I am creating a multi-agent LangGraph pipeline using `StateGraph` and `create_agent` from LangChain. Each sub-agent has its own tools plus a dynamically created “handoff” tool that returns a `Command` to transfer control to another subgraph. The tool is defined as follows: ```python @tool(name, description=description) def handoff_tool( tool_call_id: Annotated[str, InjectedToolCallId], state: Annotated[MessagesState, InjectedState], ) -> Command: tool_message = { "role": "tool", "name": name, "content": f"Successfully transferred control to {target_agent}.", "tool_call_id": tool_call_id, } return Command( goto=target_agent, update={"message": state["messages"] + [tool_message]}, graph=Command.PARENT, ) ``` When this tool is called by the model, LangGraph raises the above error instead of injecting the current `state`. It seems that `InjectedState` is not being passed to tools created via LangChain’s `@tool` decorator or `create_agent()` API. --- ### **Expected Behavior** - The tool should receive the active `MessagesState` via the `InjectedState` parameter. - The tool should be able to return a `Command` that includes `state["messages"]` for merging into the parent graph as seen in one of the examples here [https://langchain-ai.github.io/langgraph/agents/multi-agent/#handoffs](https://langchain-ai.github.io/langgraph/agents/multi-agent/#handoffs) - The state should persist across subgraph boundaries (i.e., the next agent should see the full conversation so far). --- ### **Actual Behavior** - The model calls the tool with `{}` (no arguments). - LangGraph raises an error saying `state: Field required`. - The handoff fails, and the next subgraph never receives previous context. --- ### **Environment** **Dependencies:** ```toml dependencies = [ "langchain>=1.0.2", "langchain-groq>=1.0.0", "langchain-mcp-adapters>=0.1.11", "langgraph>=1.0.1", "langsmith>=0.4.37", ] ``` --- ### **Additional Context** The example shown on the langgraph/agents/multi-agent documentation is still using the deprecated `create_react_agent`. The migration guide however does not mention anything that should change besides the import and function name. If this is intended, there should be documentation clarifying that `InjectedState` is not supported for tools passed through LangChain’s agent wrappers. ### System Info System Information ------------------ > OS: Linux > OS Version: #1 SMP PREEMPT_DYNAMIC Thu Jun 5 18:30:46 UTC 2025 > Python Version: 3.10.12 (main, Aug 15 2025, 14:32:43) [GCC 11.4.0] Package Information ------------------- > langchain_core: 1.0.0 > langchain: 1.0.2 > langsmith: 0.4.37 > langchain_groq: 1.0.0 > langchain_mcp_adapters: 0.1.11 > langgraph_sdk: 0.2.9 Optional packages not installed ------------------------------- > langserve Other Dependencies ------------------ > claude-agent-sdk: Installed. No version info available. > groq: 0.33.0 > httpx: 0.28.1 > jsonpatch: 1.33 > langchain-anthropic: Installed. No version info available. > langchain-aws: Installed. No version info available. > langchain-community: 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-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-together: Installed. No version info available. > langchain-xai: Installed. No version info available. > langgraph: 1.0.1 > langsmith-pyo3: Installed. No version info available. > mcp: 1.18.0 > openai-agents: Installed. No version info available. > opentelemetry-api: Installed. No version info available. > opentelemetry-exporter-otlp-proto-http: Installed. No version info available. > opentelemetry-sdk: Installed. No version info available. > orjson: 3.11.3 > packaging: 25.0 > pydantic: 2.12.3 > pytest: Installed. No version info available. > pyyaml: 6.0.3 > requests: 2.32.5 > requests-toolbelt: 1.0.0 > rich: Installed. No version info available. > tenacity: 9.1.2 > typing-extensions: 4.15.0 > vcrpy: Installed. No version info available. > zstandard: 0.25.0
yindo added the bugpending labels 2026-02-20 17:42:47 -05:00
yindo closed this issue 2026-02-20 17:42:47 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langchain-ai/langgraph#1025