Skip to main content
LangGraph’s pattern is interrupt/resume rather than Temporal’s signal-based approach. Inside a node, await_human() calls LangGraph’s interrupt(...), which raises and parks the graph. The DRIVER (the code running the graph) catches our shaped interrupt, posts the task to the awaithumans server, polls until terminal, and resumes the graph with the human’s response.
Single-process. Unlike the Temporal example, no separate worker or web server.

Install

Node side

await_human() is synchronous — matches LangGraph’s node API. The driver loop handles the actual blocking.

Driver side

drive_human_loop:
  1. Streams the graph forward
  2. Catches our shaped interrupt (anything with the magic awaithumans key)
  3. POSTs the task to the awaithumans server
  4. Long-polls until terminal
  5. Resumes the graph with Command(resume=response)
  6. Returns the graph’s final state
Other interrupts (operator confirmations, branching decisions) flow through unchanged — the driver pattern-matches on the awaithumans key, doesn’t grab everything.

Re-execution semantics

LangGraph re-executes the entire node on resume. Any work BEFORE await_human(...) runs twice. Move expensive or non-idempotent work to a separate node downstream:

Error contract

The driver maps polling status to typed exceptions: Catch them where you call drive_human_loop to recover.

Why this works under failure

  • Driver process dies during the await — LangGraph’s checkpointer (e.g. SQLite, Postgres, Redis) persists graph state. Re-running the script with the same thread_id resumes from the parked node. The deterministic idempotency_key (default: langgraph:{sha256(task,payload)}) means the awaithumans server returns the existing task.
  • awaithumans server restarts — tasks are persisted; on restart the dashboard reconnects and the polling driver resumes.
  • Human times outdrive_human_loop raises TaskTimeoutError. Catch it, retry with a different reviewer, or fail closed.

End-to-end example

Two runnable examples in the repo, same flow in each language: Both runnable on a laptop in three terminal windows alongside awaithumans dev. See the per-example README for the run commands.

Cross-language

The TypeScript adapter at awaithumans/langgraph produces the same wire format. A TS driver can resume a graph paused under Python and vice versa.

Common gotchas

  • No checkpointer = no interrupts. LangGraph requires a checkpointer to support interrupt(...). Production graphs should use a durable backend (SQLite / Postgres / Redis), not MemorySaver.
  • Side effects before await_human. Run twice on resume. Move them after, or wrap in idempotency.
  • Multiple await_human calls in one node. Each interrupts independently; LangGraph routes resume values by call order. Pass distinct idempotency_key= if the (task, payload) tuples might collide.

Where to next

  • Webhooks (callback_url) — wire format and signature scheme for the callback your driver receives
  • Testing — patterns for testing graph nodes that call await_human
  • Temporal adapter — the same pattern with signals instead of interrupt/resume