Hello everyone. I’ve been building a fairly complex agent workflow with LangGraph and have hit a persistent state issue that’s been driving me a bit batty for the last two days. I’m hoping someone with a deeper dive into the library’s internals can point out my likely oversight.
In essence, my graph’s `State` seems to be carrying over between completely separate invocations of `graph.invoke()`. I’ve designed this as a request-scoped service, so each new user interaction should start with a fresh state. Instead, I’m finding conversation history and tool call results from a previous session appearing in a brand new session. This suggests state is being stored in the graph object itself, but I was under the impression that `invoke` created a new execution context.
Here’s a simplified version of my graph construction:
```python
from langgraph.graph import StateGraph, END
from typing import TypedDict, Annotated
from langgraph.graph.message import add_messages
import operator
class State(TypedDict):
messages: Annotated[list, add_messages]
user_query: str
extracted_data: dict
def node_processor(state: State):
# ... processes state, uses tools
return {"extracted_data": {"new_key": "value"}}
builder = StateGraph(State)
builder.add_node("process", node_processor)
builder.set_entry_point("process")
builder.add_edge("process", END)
graph = builder.compile()
# First invocation
result1 = graph.invoke({"user_query": "First query", "messages": []})
print(f"Run 1 extracted_data: {result1['extracted_data']}")
# Second, intended-to-be-fresh invocation
result2 = graph.invoke({"user_query": "Second query", "messages": []})
print(f"Run 2 extracted_data: {result2['extracted_data']}")
```
In my actual code, `node_processor` modifies state, including the `messages` list. The issue is that when I inspect `result2`, its `extracted_data` sometimes contains data that was only generated during `result1`. The `messages` list also seems to accumulate.
My core question: **Is the compiled `Graph` object inherently stateful across `invoke` calls if your nodes modify the state in-place?** Or should each `invoke` truly start from the input state provided, implying my bug is elsewhere?
I’ve checked for obvious culprits:
* I'm not using a `MemorySaver` for persistence (this is purely in-memory).
* I'm not accidentally reusing a mutable default argument in any function.
* The `State` definition uses `add_messages` for the list, which I know is designed for aggregation. Could this be the root cause? Does `add_messages` have some static registry?
Any insights into the intended lifecycle of the `State` object would be immensely helpful. I’m trying to adhere to best practices for a clean, stateless service pattern, and this has me stumped.
—Felix
Yep, that's a classic one. Your suspicion about state living in the graph object is on point. When you define your State class and `add_messages` function, that becomes the schema for the graph's memory.
The key is that `graph.invoke()` starts from whatever you pass as the *initial* state. If you don't pass a fresh one, it might default to or retain values. Are you calling it like `graph.invoke({"messages": [], "user_query": "..."})` for each new session? If you're just passing `{"user_query": "..."}`, the `messages` and `extracted_data` keys could be hanging around from the previous run's final state.
Could you show how you're actually calling `invoke`? That's usually where the persistence sneaks in.
✌️