What is .update_state()?
.update_state() injects new values into a LangGraph thread's state without running any graph node. It is the mechanism for human-in-the-loop workflows: you pause a graph at an interrupt_before or interrupt_after node, present state to a human reviewer, receive their decision, and then write it back into the thread's checkpoint with update_state() before resuming execution.
The values argument is a dict whose keys match your state TypedDict schema. The keys you provide are merged into the existing state — you do not need to supply the full state on every call. If your state has a reducer (like add_messages, which appends rather than replaces), the reducer applies to the new values too, so passing {"messages": [HumanMessage("approved")]} will append that message rather than overwrite the messages list.
The optional as_node parameter is particularly useful when your state uses per-node reducers or when you want the update to appear as if it came from a specific node. Passing as_node="human_review" causes LangGraph to record the update as if it were that node's output, which affects which state history entry is created and which reducers are applied. After calling update_state(), resume execution by calling graph.invoke(None, config) with the same thread_id — passing None as input tells LangGraph to resume from the saved checkpoint rather than start fresh.
Use Cases
- • Human-in-the-loop
- • Resume after interrupt
- • State updates
- • User input injection
- • Interactive workflows
- • Async decision making
Key Features
- ✓ State update
- ✓ Resume execution
- ✓ Human input
- ✓ Flexible updates
- ✓ Interrupt recovery
- ✓ Workflow control
When NOT to Use
For normal execution—use invoke().
Notes
thread_id must match the interrupted graph's thread
update_state() writes to the checkpoint identified by thread_id. If you use a different thread_id than the one the graph was invoked with, you create a new checkpoint in a different thread — the interrupted graph remains paused and will never resume. Always extract the thread_id from the original invocation config.
Reducers apply to update_state() values too
If your state has a field annotated with a reducer (e.g., messages: Annotated[list, add_messages]), passing {"messages": [new_msg]} in update_state() appends the message rather than replacing the list. If you intend to replace the entire field value, use a custom reducer that overwrites rather than merges.
as_node controls which node's output the update mimics
By default, update_state() writes from the perspective of the most recently executed node. Pass as_node="node_name" to attribute the update to a specific node — useful when the graph has conditional edges that inspect which node ran last, or when per-node reducers depend on the source node identity.
Resume with graph.invoke(None, config) not graph.invoke({}, config)
Passing None as the input to invoke() after update_state() tells LangGraph to resume from the saved checkpoint. Passing an empty dict {} or a new input dict causes LangGraph to start from the beginning, losing your human-injected state. The None resume pattern is the canonical human-in-the-loop idiom.
Method Signature
graph.update_state(config, values)
Parameters
| Parameter | Type | Required | Purpose |
|---|---|---|---|
| config | dict | Yes | Config with thread_id |
Return Value
Type:
None
Description:
Updates state
Code Examples
Update state and resume after interrupt
config = {'configurable': {'thread_id': '1'}}
# After interrupt, inject human decision
graph.update_state(
config,
{'user_input': 'approved — proceed'}
)
# Resume from the checkpoint
result = graph.invoke(None, config)
Update with as_node for reducer-aware injection
from langchain_core.messages import HumanMessage
config = {'configurable': {'thread_id': 'thread-7'}}
snapshot = graph.get_state(config)
print('Waiting at:', snapshot.next)
# Append a human message and record it as the 'review' node output
graph.update_state(
config,
{'messages': [HumanMessage(content='Looks good')]},
as_node='human_review'
)
result = graph.invoke(None, config)
Correct mid-flight state for debugging
config = {'configurable': {'thread_id': 'debug-99'}}
# Correct a wrong state value mid-flight
graph.update_state(config, {'draft': 'revised content here'})
# Verify the change took effect
print(graph.get_state(config).values['draft'])
Common Mistakes
❌ Update state without proper thread context
✅ Ensure config has correct thread_id
Related LangChain References
Browse the full LangChain API reference index to explore more classes, methods, and decorators, or start with the LangChain introduction tutorial for end-to-end context on building with .update_state() and the wider framework.
.update_state() FAQ
What does .update_state() do in LangChain?
Update and resume graph execution. .update_state() injects new values into a LangGraph thread's state without running any graph node. It is the mechanism for human-in-the-loop workflows: you pause a graph at an interrupt_before or interrupt_after node, present state to a human reviewer, receive their decision, and then write it back into the thread's checkpoint with update_state() before resuming execution. The values argument is a dict whose keys match your state TypedDict schema. The keys you provide are me…
Which LangChain classes support .update_state()?
.update_state() is available on CompiledStateGraph. Pin your installed LangChain version and verify the method exists in that release before deploying.
When should I use .update_state()?
Use .update_state() when your LangChain chains, agents, or pipelines need the behavior described in this guide.
What does .update_state() return?
See the Return Value section above for the exact type and shape .update_state() produces.
Does .update_state() have an async equivalent?
.update_state() does not have a documented async variant. Avoid .update_state() For normal execution—use invoke().
Where can I explore more LangChain API reference pages?
Open the LangChain API reference index on DevShelfHub to browse classes, methods, and decorators, each with runnable examples, parameters, common mistakes, and cross-links.