Zenaique

Fill in the LangGraph primitives that pause a graph for human input and resume it later

Fill in blank·Medium·4.0 · 0·~1 min·Asked atCoreweaveFlipkartPolyai
Attempt it
To pause a LangGraph thread before a specific node and wait for a human decision, configure the graph with (or call inside the node), and persist progress via a so the same thread can resume after `update_state` carries the human input back in.
TL;DR

Pause with `interrupt_before` at compile time or `interrupt()` inside a node; persist with a checkpointer so the thread can resume after restart.

Memory aid
Sign in to see the mnemonic that makes this stick.
Easy to grasp

Imagine a board game where you sometimes have to wait for another player before you can take your turn. You need two things: a rule that says 'stop here and ask the other player,' and a notebook where you write down the state of the board so the game can be paused for a week and resumed on the same square. Without the rule you cannot pause; without the notebook you cannot resume after a coffee break. LangGraph's interrupts are the rule, and the checkpointer is the notebook.

Key concepts

Concept explanation~2 min read

Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.

Human in the loop sounds like a UX feature and turns out to be a distributed-systems feature. Pausing a workflow while a human decides means surviving process restarts, multi-instance deployments, network partitions, and the simple reality that humans take minutes to days to respond. LangGraph's answer is to treat HITL as durable workflow state: a pause primitive that yields execution and a persistence primitive that survives anything short of database loss.

The two primitives have to be configured together. Either alone is a footgun: a pause without persistence works only within one process lifetime; persistence without a pause hook is a stateful machine with no way to wait for external input.

This deep dive walks the two pause variants, the four checkpointer options and their operational trade-offs, the resumption mechanics with update_state and as_node, the latency budget of checkpointing, and the bonus side effect that the same mechanism enables time-travel debugging.

The two pause primitives: static and dynamic

Static pause: interrupt_before and interrupt_after. Declared at compile time on the graph object: graph.compile(checkpointer=cp, interrupt_before=['approval_node']). The runtime checks before (or after) the named nodes and yields to the caller via an interrupt event on the stream. This is the right pick when the pause point is a fixed node that always requires external input. Example: an approval_node that always asks a human before sending an outbound email.

Dynamic pause: interrupt(value). Called from inside a node body. The function pauses execution immediately and emits the value through the stream's interrupt event. Resumption with Command(resume=human_input) lets the human's response become the function's return value. This is the right pick when the pause condition depends on state: 'pause only when confidence is below 0.7,' 'pause only when the tool call is to a dangerous endpoint,' 'pause only when the cumulative cost crosses a threshold.'

Mixing both in one graph is supported. A typical pattern is interrupt_before=['high_stakes_node'] for guaranteed pauses plus dynamic interrupt() calls inside other nodes for state-conditional pauses.

The event shapes are slightly different. Static interrupts surface as __interrupt__ events with the pending node name; dynamic interrupts surface as interrupt events with the value. The application code that consumes the stream needs to handle both shapes if both are used.

The four checkpointer options and their trade-offs
Threads, resumption, and update_state
Latency budget and state design
Time-travel debugging as a free side effect
Sign in to unlock the full deep dive.

Situations where this technique stops working.

Sign in to see when this approach fails.

2–4 min · Everything important, quickly.

Sign in to see the quick scan of the deep dive.

Real products, models, and research that use this idea.

  • Linear's AI features use LangGraph with Postgres checkpointing for the issue-triage flow that occasionally needs human approval before posting a comment.
  • Devin (Cognition AI) reportedly uses a LangGraph-style state machine with durable checkpointing for long-horizon coding tasks.
Sign in to see more production examples.

What an interviewer would ask next. Try answering before peeking at the approach.

QWalk through the exact sequence of calls for a HITL approval flow.
A
  1. Configure graph with interrupt_before=['approval_node'] and a PostgresSaver checkpointer. 2) Call graph.stream(initial_input, {'configurable': {'thread_id': tid}}). 3) The stream yields events until the approval node; an interrupt event is emitted. 4) Application surfaces the pending state to a human. 5) Human decides; application calls graph.update_state(thread_config, {'approved': True}, as_node='approval_node'). 6) Application calls graph.stream(None, thread_config) to resume from the next step.
2 more follow-ups an interviewer would ask next. Sign in to reveal them.

Red flags & common mistakes

The phrases that signal junior thinking. Click to expand.

Most common mistake

Configuring `interrupt_before` without setting a checkpointer. The graph will pause but cannot survive a process restart, so the 'pause' only works within one process lifetime.

Sign in to see all red flags and common mistakes.

60 second bullets to scan on the way to the call.

  • The two pause variants: interrupt_before / interrupt_after and the dynamic interrupt() function

  • The four checkpointer options: PostgresSaver, SqliteSaver, RedisSaver, MemorySaver

Sign in to unlock the revision sheet.

Primary sources. Browse if you want the original framing.

Similar questions

Same topic, related formats. Practice these next.

4 curated
Next question
Defend the call to…
Short answer·Hard