Agent created with create_react_agent does not retain private state properties passed from earlier nodes in the graph, causing validation error #996

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

Originally created by @BEATING-HEART on GitHub (Sep 30, 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

from langgraph.graph import END, START, StateGraph
from langgraph.graph.message import AnyMessage, add_messages
from langgraph.prebuilt import create_react_agent
from langgraph.prebuilt.chat_agent_executor import (
    AgentState,
    AgentStateWithStructuredResponse,
    AgentStateWithStructuredResponsePydantic,
)
from pydantic import BaseModel
from typing_extensions import TypedDict

# class State(TypedDict):
class State(BaseModel):
    a: str

# class PrivateState(AgentStateWithStructuredResponse):
class PrivateState(AgentStateWithStructuredResponsePydantic):
    private_data: int

def pre_agent(state: State) -> PrivateState:
    output = {"private_data": 100}
    print(f"Entered node `pre_agent`:\n\tInput: {state}.\n\tReturned: {output}")
    # s = PrivateState(private_data=100, structured_response={}, messages=[])
    # return s
    return output

agent = create_react_agent(
    name="agent",
    model="openai:gpt-5",
    tools=[],
    state_schema=PrivateState,
    prompt="Say hello. and put your response in the structured response object",
    response_format=State,
)

def post_agent(state: PrivateState) -> State:
    # print(state)
    # output = {"a": "set by post_agent"}
    output = state["structured_response"]
    print(f"Entered node `post_agent`:\n\tInput: {state}.\n\tReturned: {output}")
    return output

builder = StateGraph(State).add_sequence([pre_agent, agent, post_agent])
builder.add_edge(START, "pre_agent")
graph = builder.compile()

response = graph.invoke(
    {
        "a": "set at start",
    }
)

print()
print(f"Output of graph invocation: {response}")

Error Message and Stack Trace (if applicable)

# Stack Trace

    
        # Invoke the graph with the initial state
>       response = graph.invoke(
            {
                "a": "set at start",
            }
        )

test/test_llm.py:229: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/pregel/main.py:3026: in invoke
    for chunk in self.stream(
../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/pregel/main.py:2647: in stream
    for _ in runner.tick(
../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/pregel/_runner.py:162: in tick
    run_with_retry(
../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/pregel/_retry.py:42: in run_with_retry
    return task.proc.invoke(task.input, config)
../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/_internal/_runnable.py:657: in invoke
    input = context.run(step.invoke, input, config, **kwargs)
../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/pregel/main.py:3026: in invoke
    for chunk in self.stream(
../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/pregel/main.py:2647: in stream
    for _ in runner.tick(
../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/pregel/_runner.py:162: in tick
    run_with_retry(
../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/pregel/_retry.py:42: in run_with_retry
    return task.proc.invoke(task.input, config)
../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/_internal/_runnable.py:657: in invoke
    input = context.run(step.invoke, input, config, **kwargs)
../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/pregel/main.py:3026: in invoke
    for chunk in self.stream(
../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/pregel/main.py:2644: in stream
    while loop.tick():
../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/pregel/_loop.py:455: in tick
    self.tasks = prepare_next_tasks(
../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/pregel/_algo.py:470: in prepare_next_tasks
    if task := prepare_single_task(
../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/pregel/_algo.py:806: in prepare_single_task
    val = _proc_input(
../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/pregel/_algo.py:1054: in _proc_input
    val = proc.mapper(val)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

schema = <class 'test.test_llm.test_private_state_agent.<locals>.PrivateState'>, input = {'messages': [], 'remaining_steps': 24}

    def _coerce_state(schema: type[Any], input: dict[str, Any]) -> dict[str, Any]:
>       return schema(**input)
E       pydantic_core._pydantic_core.ValidationError: 2 validation errors for PrivateState
E       structured_response
E         Field required [type=missing, input_value={'messages': [], 'remaining_steps': 24}, input_type=dict]
E           For further information visit https://errors.pydantic.dev/2.10/v/missing
E       private_data
E         Field required [type=missing, input_value={'messages': [], 'remaining_steps': 24}, input_type=dict]
E           For further information visit https://errors.pydantic.dev/2.10/v/missing

../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/graph/state.py:1230: ValidationError
======================================================================= short test summary info ========================================================================
FAILED test/test_llm.py::test_private_state_agent - pydantic_core._pydantic_core.ValidationError: 2 validation errors for PrivateState

Description

When calling create_react_agent, I encountered a Pydantic validation error. The traceback shows it is caused by AgentStateWithStructuredResponsePydantic.

Expected behavior: The agent should return a valid structured response that matches the schema.

Actual behavior: Validation fails inside AgentStateWithStructuredResponsePydantic.

PS: The code works correctly if State inherits from TypedDict, and PrivateState inherits from AgentStateWithStructuredResponse.

System Info

System Information

OS: Linux
OS Version: #61~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Tue Apr 15 17:03:15 UTC 2
Python Version: 3.10.16 (main, Dec 11 2024, 16:24:50) [GCC 11.2.0]

Package Information

langchain_core: 0.3.75
langchain: 0.3.27
langchain_community: 0.3.25
langsmith: 0.3.45
langchain_modelscope: Installed. No version info available.
langchain_ollama: 0.3.3
langchain_openai: 0.2.14
langchain_text_splitters: 0.3.11
langgraph_sdk: 0.2.4


Update 1: create_react_agent does not retain private properties passed along from earlier nodes in the graph

Example Code:

from langchain_core.messages import HumanMessage, SystemMessage
from langchain_core.prompts import SystemMessagePromptTemplate
from langgraph.graph import END, START, StateGraph
from langgraph.graph.message import AnyMessage, add_messages
from langgraph.prebuilt import create_react_agent
from langgraph.prebuilt.chat_agent_executor import (
    AgentState,
    AgentStateWithStructuredResponse,
    AgentStateWithStructuredResponsePydantic,
)
from pydantic import BaseModel
from typing_extensions import TypedDict

class State(TypedDict):
    # class State(BaseModel):
    name: str

class PrivateState(AgentStateWithStructuredResponse):
    # class PrivateState(AgentStateWithStructuredResponsePydantic):
    id: int
    name: str

class Response(TypedDict):
    greeting: str

def pre_agent(state: State) -> PrivateState:
    id = 65535
    output = PrivateState(name=state["name"], id=id, messages=[])
    print(f"[pre_agent] id set to {id}")
    return output

def get_prompt(state):
    if "id" not in state:
        print("[agent/get prompt] id not loaded")

    return [
        SystemMessage("Say hello, and add his id in your greeting."),
        HumanMessage(f"current state: {state}"),
    ]

def pre_model_hook(state):
    if "id" in state:
        print(f"[agent/pre_model_hook] id = {state['id']}")
    else:
        print("[agent/pre_model_hook] id not loaded")

def post_model_hook(state):
    if "id" in state:
        print(f"[agent/post_model_hook] id = {state['id']}")
    else:
        print("[agent/post_model_hook] id not loaded")

agent = create_react_agent(
    name="agent",
    model="openai:gpt-5",
    tools=[],
    state_schema=PrivateState,
    prompt=get_prompt,
    pre_model_hook=pre_model_hook,
    post_model_hook=post_model_hook,
    response_format=Response,
)

def post_agent(state: PrivateState) -> State:
    print(f"[post_agent] {type(state)}")
    print(f"[post_agent] state keys = {state.keys()}")
    if "id" in state:
        print(f"[post_agent] id = {state['id']}")

    output = state["structured_response"]
    print(f"[post_agent] output = {output}")
    return output

builder = StateGraph(State).add_sequence([pre_agent, agent, post_agent])
builder.add_edge(START, "pre_agent")
graph = builder.compile()

response = graph.invoke(
    {
        "name": "Jack",
    }
)

print()
print(f"Output of graph invocation: {response}")

Outputs:

[pre_agent] id set to 65535
[agent/pre_model_hook] id not loaded  
[agent/get prompt] id not loaded
[agent/post_model_hook] id not loaded
[post_agent] <class 'dict'>
[post_agent] state keys = dict_keys(['messages', 'structured_response', 'id', 'name', 'remaining_steps'])
[post_agent] id = 65535
[post_agent] output = {'greeting': 'Hello, Jack! How can I assist you today?'}

Output of graph invocation: {'name': 'Jack'}

Description

Expected behavior: agent should have access to private property id.

Current behavior:
the private state is correctly constructed in pre_agent node and private property id can be accessed in the post_agent node. However, it remains hidden from the agent node.

Langgraph v1-alpha seems to have the same issue.

Originally created by @BEATING-HEART on GitHub (Sep 30, 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 from langgraph.graph import END, START, StateGraph from langgraph.graph.message import AnyMessage, add_messages from langgraph.prebuilt import create_react_agent from langgraph.prebuilt.chat_agent_executor import ( AgentState, AgentStateWithStructuredResponse, AgentStateWithStructuredResponsePydantic, ) from pydantic import BaseModel from typing_extensions import TypedDict # class State(TypedDict): class State(BaseModel): a: str # class PrivateState(AgentStateWithStructuredResponse): class PrivateState(AgentStateWithStructuredResponsePydantic): private_data: int def pre_agent(state: State) -> PrivateState: output = {"private_data": 100} print(f"Entered node `pre_agent`:\n\tInput: {state}.\n\tReturned: {output}") # s = PrivateState(private_data=100, structured_response={}, messages=[]) # return s return output agent = create_react_agent( name="agent", model="openai:gpt-5", tools=[], state_schema=PrivateState, prompt="Say hello. and put your response in the structured response object", response_format=State, ) def post_agent(state: PrivateState) -> State: # print(state) # output = {"a": "set by post_agent"} output = state["structured_response"] print(f"Entered node `post_agent`:\n\tInput: {state}.\n\tReturned: {output}") return output builder = StateGraph(State).add_sequence([pre_agent, agent, post_agent]) builder.add_edge(START, "pre_agent") graph = builder.compile() response = graph.invoke( { "a": "set at start", } ) print() print(f"Output of graph invocation: {response}") ``` ### Error Message and Stack Trace (if applicable) ```shell # Stack Trace # Invoke the graph with the initial state > response = graph.invoke( { "a": "set at start", } ) test/test_llm.py:229: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/pregel/main.py:3026: in invoke for chunk in self.stream( ../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/pregel/main.py:2647: in stream for _ in runner.tick( ../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/pregel/_runner.py:162: in tick run_with_retry( ../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/pregel/_retry.py:42: in run_with_retry return task.proc.invoke(task.input, config) ../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/_internal/_runnable.py:657: in invoke input = context.run(step.invoke, input, config, **kwargs) ../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/pregel/main.py:3026: in invoke for chunk in self.stream( ../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/pregel/main.py:2647: in stream for _ in runner.tick( ../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/pregel/_runner.py:162: in tick run_with_retry( ../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/pregel/_retry.py:42: in run_with_retry return task.proc.invoke(task.input, config) ../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/_internal/_runnable.py:657: in invoke input = context.run(step.invoke, input, config, **kwargs) ../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/pregel/main.py:3026: in invoke for chunk in self.stream( ../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/pregel/main.py:2644: in stream while loop.tick(): ../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/pregel/_loop.py:455: in tick self.tasks = prepare_next_tasks( ../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/pregel/_algo.py:470: in prepare_next_tasks if task := prepare_single_task( ../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/pregel/_algo.py:806: in prepare_single_task val = _proc_input( ../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/pregel/_algo.py:1054: in _proc_input val = proc.mapper(val) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ schema = <class 'test.test_llm.test_private_state_agent.<locals>.PrivateState'>, input = {'messages': [], 'remaining_steps': 24} def _coerce_state(schema: type[Any], input: dict[str, Any]) -> dict[str, Any]: > return schema(**input) E pydantic_core._pydantic_core.ValidationError: 2 validation errors for PrivateState E structured_response E Field required [type=missing, input_value={'messages': [], 'remaining_steps': 24}, input_type=dict] E For further information visit https://errors.pydantic.dev/2.10/v/missing E private_data E Field required [type=missing, input_value={'messages': [], 'remaining_steps': 24}, input_type=dict] E For further information visit https://errors.pydantic.dev/2.10/v/missing ../../software/miniconda/envs/car310/lib/python3.10/site-packages/langgraph/graph/state.py:1230: ValidationError ======================================================================= short test summary info ======================================================================== FAILED test/test_llm.py::test_private_state_agent - pydantic_core._pydantic_core.ValidationError: 2 validation errors for PrivateState ``` ### Description When calling create_react_agent, I encountered a Pydantic validation error. The traceback shows it is caused by AgentStateWithStructuredResponsePydantic. Expected behavior: The agent should return a valid structured response that matches the schema. Actual behavior: Validation fails inside AgentStateWithStructuredResponsePydantic. PS: The code works correctly if `State` inherits from `TypedDict`, and `PrivateState` inherits from `AgentStateWithStructuredResponse`. ### System Info > System Information ------------------ > OS: Linux > OS Version: #61~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Tue Apr 15 17:03:15 UTC 2 > Python Version: 3.10.16 (main, Dec 11 2024, 16:24:50) [GCC 11.2.0] Package Information ------------------- > langchain_core: 0.3.75 > langchain: 0.3.27 > langchain_community: 0.3.25 > langsmith: 0.3.45 > langchain_modelscope: Installed. No version info available. > langchain_ollama: 0.3.3 > langchain_openai: 0.2.14 > langchain_text_splitters: 0.3.11 > langgraph_sdk: 0.2.4 ---------------- ## Update 1: `create_react_agent` does not retain private properties passed along from earlier nodes in the graph ### Example Code: ```python from langchain_core.messages import HumanMessage, SystemMessage from langchain_core.prompts import SystemMessagePromptTemplate from langgraph.graph import END, START, StateGraph from langgraph.graph.message import AnyMessage, add_messages from langgraph.prebuilt import create_react_agent from langgraph.prebuilt.chat_agent_executor import ( AgentState, AgentStateWithStructuredResponse, AgentStateWithStructuredResponsePydantic, ) from pydantic import BaseModel from typing_extensions import TypedDict class State(TypedDict): # class State(BaseModel): name: str class PrivateState(AgentStateWithStructuredResponse): # class PrivateState(AgentStateWithStructuredResponsePydantic): id: int name: str class Response(TypedDict): greeting: str def pre_agent(state: State) -> PrivateState: id = 65535 output = PrivateState(name=state["name"], id=id, messages=[]) print(f"[pre_agent] id set to {id}") return output def get_prompt(state): if "id" not in state: print("[agent/get prompt] id not loaded") return [ SystemMessage("Say hello, and add his id in your greeting."), HumanMessage(f"current state: {state}"), ] def pre_model_hook(state): if "id" in state: print(f"[agent/pre_model_hook] id = {state['id']}") else: print("[agent/pre_model_hook] id not loaded") def post_model_hook(state): if "id" in state: print(f"[agent/post_model_hook] id = {state['id']}") else: print("[agent/post_model_hook] id not loaded") agent = create_react_agent( name="agent", model="openai:gpt-5", tools=[], state_schema=PrivateState, prompt=get_prompt, pre_model_hook=pre_model_hook, post_model_hook=post_model_hook, response_format=Response, ) def post_agent(state: PrivateState) -> State: print(f"[post_agent] {type(state)}") print(f"[post_agent] state keys = {state.keys()}") if "id" in state: print(f"[post_agent] id = {state['id']}") output = state["structured_response"] print(f"[post_agent] output = {output}") return output builder = StateGraph(State).add_sequence([pre_agent, agent, post_agent]) builder.add_edge(START, "pre_agent") graph = builder.compile() response = graph.invoke( { "name": "Jack", } ) print() print(f"Output of graph invocation: {response}") ``` **Outputs:** ```txt [pre_agent] id set to 65535 [agent/pre_model_hook] id not loaded [agent/get prompt] id not loaded [agent/post_model_hook] id not loaded [post_agent] <class 'dict'> [post_agent] state keys = dict_keys(['messages', 'structured_response', 'id', 'name', 'remaining_steps']) [post_agent] id = 65535 [post_agent] output = {'greeting': 'Hello, Jack! How can I assist you today?'} Output of graph invocation: {'name': 'Jack'} ``` ### Description Expected behavior: `agent` should have access to private property `id`. Current behavior: the private state is correctly constructed in `pre_agent` node and private property `id` can be accessed in the `post_agent` node. However, it remains hidden from the `agent` node. **Langgraph v1-alpha seems to have the same issue.**
yindo added the bugpending labels 2026-02-20 17:42:39 -05:00
yindo closed this issue 2026-02-20 17:42:39 -05:00
Author
Owner

@sarathak commented on GitHub (Sep 30, 2025):

I’m trying to understand how this is supposed to work.

The Graph is defined with a State, so expected to just pass the State to all nodes. But it seems that’s not happening—looking at the React agent, only the State appears to be passed.

Is this the expected behaviour? @sydney-runkle

builder = StateGraph(State).add_sequence([pre_agent, agent, post_agent])

changed to

builder = StateGraph(PrivateState).add_sequence([pre_agent, agent, post_agent])

it will work perfect

@sarathak commented on GitHub (Sep 30, 2025): I’m trying to understand how this is supposed to work. The Graph is defined with a State, so expected to just pass the State to all nodes. But it seems that’s not happening—looking at the React agent, only the State appears to be passed. Is this the expected behaviour? @sydney-runkle ```builder = StateGraph(State).add_sequence([pre_agent, agent, post_agent])``` changed to ```builder = StateGraph(PrivateState).add_sequence([pre_agent, agent, post_agent])``` it will work perfect
Author
Owner

@BEATING-HEART commented on GitHub (Sep 30, 2025):

Thank you for your reply, your suggestion works. However, that will lead to a large overall state if the workflow is complex.

The private state works smoothly with normal nodes (even under Pydantic)

docs: https://langchain-ai.github.io/langgraph/how-tos/graph-api/?h=private#pass-private-state-between-nodes
code: attached below

Since create_react_agent returns a CompiledStateGraph with PrivateState as its state_schema, it seems like passing the private state to the agent should work, but it fails

For better cohesion, private state operations could be managed inside the agent via hooks (pre_model_hook, post_model_hook, etc.) or hook-like methods/properties (model, prompt). Another option is to introduce pre_agent_hook or post_agent_hook as adapters.

So, retain the private properties passed from prior node for agent make sense.

# private state works well with normal nodes.
from langgraph.graph import START, StateGraph
from pydantic import BaseModel

class State(BaseModel):
    name: str

class PrivateState(BaseModel):
    id: int
    name: str

def node_1(state: State) -> PrivateState:
    id = 65535
    output = PrivateState(name=state.name, id=id)
    print(f"[node_1] Input: {state}")
    print(f"[node_1] Output: {output}")
    return output

def node_2(state: PrivateState) -> State:
    output = State(name=state.name)
    print(f"[node_2] Input: {state}")
    print(f"[node_2] Output: {output}")
    return output

def node_3(state: State) -> State:
    output = State(name="Bob")
    print(f"[node_3] Input: {state}")
    print(f"[node_3] Output: {output}")
    return output

builder = StateGraph(State).add_sequence([node_1, node_2, node_3])
builder.add_edge(START, "node_1")
graph = builder.compile()

response = graph.invoke(
    {
        "name": "Jack",
    }
)

print()
print(f"Output of graph invocation: {response}")

Outputs:

[node_1] Input: name='Jack'
[node_1] Output: id=65535 name='Jack'
[node_2] Input: id=65535 name='Jack'
[node_2] Output: name='Jack'
[node_3] Input: name='Jack'
[node_3] Output: name='Bob'

Output of graph invocation: {'name': 'Bob'}
@BEATING-HEART commented on GitHub (Sep 30, 2025): Thank you for your reply, your suggestion works. However, that will lead to a large overall state if the workflow is complex. The private state works smoothly with normal nodes (even under Pydantic) > docs: https://langchain-ai.github.io/langgraph/how-tos/graph-api/?h=private#pass-private-state-between-nodes > code: attached below Since `create_react_agent` returns a `CompiledStateGraph` with `PrivateState` as its `state_schema`, it seems like passing the private state to the agent should work, but it fails For better cohesion, private state operations could be managed inside the agent via hooks (`pre_model_hook`, `post_model_hook`, etc.) or hook-like methods/properties (`model`, `prompt`). Another option is to introduce `pre_agent_hook` or `post_agent_hook` as adapters. So, retain the private properties passed from prior node for agent make sense. ```python # private state works well with normal nodes. from langgraph.graph import START, StateGraph from pydantic import BaseModel class State(BaseModel): name: str class PrivateState(BaseModel): id: int name: str def node_1(state: State) -> PrivateState: id = 65535 output = PrivateState(name=state.name, id=id) print(f"[node_1] Input: {state}") print(f"[node_1] Output: {output}") return output def node_2(state: PrivateState) -> State: output = State(name=state.name) print(f"[node_2] Input: {state}") print(f"[node_2] Output: {output}") return output def node_3(state: State) -> State: output = State(name="Bob") print(f"[node_3] Input: {state}") print(f"[node_3] Output: {output}") return output builder = StateGraph(State).add_sequence([node_1, node_2, node_3]) builder.add_edge(START, "node_1") graph = builder.compile() response = graph.invoke( { "name": "Jack", } ) print() print(f"Output of graph invocation: {response}") ``` **Outputs:** ```txt [node_1] Input: name='Jack' [node_1] Output: id=65535 name='Jack' [node_2] Input: id=65535 name='Jack' [node_2] Output: name='Jack' [node_3] Input: name='Jack' [node_3] Output: name='Bob' Output of graph invocation: {'name': 'Bob'} ```
Author
Owner

@sydney-runkle commented on GitHub (Nov 7, 2025):

Hiya! This should work w/ our new create_agent in langchain v1. Going to close as such!

@sydney-runkle commented on GitHub (Nov 7, 2025): Hiya! This should work w/ our new `create_agent` in langchain v1. Going to close as such!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langchain-ai/langgraph#996