# Subgraph forgets its state when the parent graph invokes it a second time

TL;DR: do not wire a compiled subgraph directly as a node when the parent calls it repeatedly. Wrap it in a node function that invokes the subgraph, and its state persists across calls. Direct wiring can cause the subgraph to run once and then silently reuse stale or empty state.

```text
# no exception. the symptom: print() inside the subgraph node fires once,
# but the parent routes to the subgraph three times. the second and third
# visits see empty state instead of the accumulated state from run one.
```

## When this applies

- A parent graph calls the same subgraph node more than once (loop, follow-up questions, retries).
- First visit works; later visits act like a fresh subgraph.
- A debug print inside the subgraph confirms it only executed once.

## When it does not

- If the PARENT loses state between separate `invoke()` calls, that is a checkpointer/thread_id issue, not this.
- If the subgraph errors, look at the actual exception instead.

## Fix it

### 1. Wrap the subgraph in a node function

```python
# instead of: parent.add_node("agent", subgraph)
# do this:

def agent_node(state: ParentState):
    # invoke the compiled subgraph fresh each time the parent visits this node
    return subgraph.invoke({"messages": state["messages"]})

parent.add_node("agent", agent_node)
```

Expected: your debug print inside the subgraph now fires on every visit, and state accumulates across visits.

### 2. Pass state in explicitly, read it back explicitly

```python
def agent_node(state: ParentState):
    result = subgraph.invoke({
        "messages": state["messages"],
        "subgraph_state": state.get("subgraph_state"),
    })
    return {"messages": result["messages"]}
```

Expected: the parent only keeps the keys it declares; the subgraph keeps its own. Nothing leaks or gets silently dropped.

### 3. Give the subgraph its own thread namespace if it has a checkpointer

If both parent and subgraph use checkpointers, the subgraph's checkpoints live under a namespace. When invoking manually, keep the namespace stable so the subgraph resumes instead of restarting:

```python
def agent_node(state: ParentState, config):
    sub_config = {"configurable": {"thread_id": config["configurable"]["thread_id"]}}
    return subgraph.invoke({"messages": state["messages"]}, sub_config)
```

Expected: `subgraph.get_state(sub_config)` shows history across parent visits.

## Why it happens

A compiled subgraph used directly as a node is treated as a single node by the parent's Pregel loop. Its internal super-steps are managed by the parent, and on repeat visits the parent may not re-enter the subgraph's own loop the way a fresh `invoke()` would. A wrapper node function makes each visit a genuine fresh invocation with its own state lifecycle.

## Edge cases

- Streaming: with the wrapper, use `subgraph.stream()` inside the node and forward events if the parent needs them.
- Interrupts inside the subgraph still work, but the interrupt surfaces at the wrapper node. Resume with the parent's config as usual.
- Performance: each visit re-enters the subgraph from its entry point. If you need the subgraph to continue mid-loop across visits, keep its checkpointer and pass the same thread config.

## Compatibility

langgraph 0.2.x and 1.x (Python). The pattern (node function wrapping `subgraph.invoke`) works in all versions.