Skip to course content
Free LangGraph course

LangGraph for Agentic Workflows

Unit 06.03: Inspecting state between steps

get_state_history is the debugger for a graph, and most people discover it after spending an afternoon adding print statements.

The state at every step, newest first

A checkpointer records a snapshot per step. The history is that sequence, and each snapshot carries both the values and what was going to run next.

The code runs a two-node graph and prints the history.

from typing import TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import InMemorySaver


class State(TypedDict):
    n: int
    trail: list


def double(state: State):
    return {"n": state["n"] * 2, "trail": state["trail"] + ["double"]}


def add(state: State):
    return {"n": state["n"] + 3, "trail": state["trail"] + ["add"]}


g = StateGraph(State)
g.add_node("double", double)
g.add_node("add", add)
g.add_edge(START, "double")
g.add_edge("double", "add")
g.add_edge("add", END)
app = g.compile(checkpointer=InMemorySaver())

config = {"configurable": {"thread_id": "inspect-1"}}
app.invoke({"n": 5, "trail": []}, config)

print("final :", app.get_state(config).values)
print("\nhistory, newest first:")
for snapshot in app.get_state_history(config):
    print(f"  next={str(snapshot.next):16} n={snapshot.values.get('n')}")

# `get_state_history` is the debugger. It shows the state at every step, which
# is how you find the node where a value first went wrong instead of guessing
# from the final result.

Each entry shows next and the value at that point. Reading it, you can see the value at the moment before each node ran - which is how you find the node where a number first became wrong, rather than inferring it from the final result.

The history is newest-first. Reversing it to read forwards is usually easier when hunting a value that went wrong, since you want the first bad one rather than the last.

The mistake this prevents

The mistake is debugging with print statements inside nodes. They tell you what a node saw only for the runs you happened to instrument, and they are gone when the bug appears in production. The history is there for every checkpointed run, including the ones you did not expect to need.

Takeaway

get_state_history gives you the state before and after every node for free on any checkpointed run. It is the first thing to reach for when a value is wrong and you do not know which node produced it.