interrupt works only for streaming #307

Closed
opened 2026-02-15 18:15:45 -05:00 by yindo · 2 comments
Owner

Originally created by @marisundar on GitHub (Jul 18, 2025).

Checked other resources

  • I added a very descriptive title to this issue.
  • I searched the LangGraph.js documentation with the integrated search.
  • I used the GitHub search to find a similar question and didn't find it.
  • I am sure that this is a bug in LangGraph.js rather than my code.
  • The bug is not resolved by updating to the latest stable version of LangGraph (or the specific integration package).

Example Code

import { MemorySaver, Annotation, interrupt, Command, StateGraph } from "@langchain/langgraph";

// Define the graph state
const StateAnnotation = Annotation.Root({
  some_text: Annotation<string>()
});

function humanNode(state: typeof StateAnnotation.State) {
   const value = interrupt(
      // Any JSON serializable value to surface to the human.
      // For example, a question or a piece of text or a set of keys in the state
      {
         text_to_revise: "Do you wish to approve ?"
      }
   );
   return {
      // Update the state with the human's input
      some_text: value
   };
}

// Build the graph
const workflow = new StateGraph(StateAnnotation)
// Add the human-node to the graph
  .addNode("human_node", humanNode)
  .addEdge("__start__", "human_node")

// A checkpointer is required for `interrupt` to work.
const checkpointer = new MemorySaver();
const graph = workflow.compile({
   checkpointer
});
const config = { configurable: { thread_id: "123" } };

// Using stream() to directly surface the `__interrupt__` information.

for await (const chunk of await graph.stream(
   { some_text: "Original text" },
   config
)) {
   console.log("Paused state", JSON.stringify(chunk));
}

// Resume using Command
for await (const chunk of await graph.stream(
   new Command({ resume: "Edited text" }),
   config
)) {
   console.log(chunk);
}

This actually prints

Paused state {"__interrupt__":[{"value":{"text_to_revise":"Do you wish to approve ?"},"when":"during","resumable":true,"ns":["human_node:256ce302-2f0b-5ba8-8eba-ec02b2bb7a82"]}]}
{ human_node: { some_text: 'Edited text' } }

But when I use invoke for the execution

import { MemorySaver, Annotation, interrupt, Command, StateGraph } from "@langchain/langgraph";

// Define the graph state
const StateAnnotation = Annotation.Root({
  some_text: Annotation<string>()
});

function humanNode(state: typeof StateAnnotation.State) {
   const value = interrupt(
      // Any JSON serializable value to surface to the human.
      // For example, a question or a piece of text or a set of keys in the state
      {
         text_to_revise: "Do you wish to approve ?"
      }
   );
   return {
      // Update the state with the human's input
      some_text: value
   };
}

// Build the graph
const workflow = new StateGraph(StateAnnotation)
// Add the human-node to the graph
  .addNode("human_node", humanNode)
  .addEdge("__start__", "human_node")

// A checkpointer is required for `interrupt` to work.
const checkpointer = new MemorySaver();
const graph = workflow.compile({
   checkpointer
});
const config = { configurable: { thread_id: "123" } };

const result = await graph.invoke({ some_text: "Original text" },config);
console.log("Paused state", JSON.stringify(result));

// Resume using Command
for await (const chunk of await graph.stream(
   new Command({ resume: "Edited text" }),
   config
)) {
   console.log(chunk);
}

I am getting only the state where it is paused

Paused state {"some_text":"Original text"}
{ human_node: { some_text: 'Edited text' } }

Error Message and Stack Trace (if applicable)

No response

Description

  • Using the streaming it is actually working
  • But using invoke it is not working

System Info

Linux
TS
NodeJS 18

Originally created by @marisundar on GitHub (Jul 18, 2025). ### Checked other resources - [x] I added a very descriptive title to this issue. - [x] I searched the LangGraph.js documentation with the integrated search. - [x] I used the GitHub search to find a similar question and didn't find it. - [x] I am sure that this is a bug in LangGraph.js rather than my code. - [x] The bug is not resolved by updating to the latest stable version of LangGraph (or the specific integration package). ### Example Code ```typescript import { MemorySaver, Annotation, interrupt, Command, StateGraph } from "@langchain/langgraph"; // Define the graph state const StateAnnotation = Annotation.Root({ some_text: Annotation<string>() }); function humanNode(state: typeof StateAnnotation.State) { const value = interrupt( // Any JSON serializable value to surface to the human. // For example, a question or a piece of text or a set of keys in the state { text_to_revise: "Do you wish to approve ?" } ); return { // Update the state with the human's input some_text: value }; } // Build the graph const workflow = new StateGraph(StateAnnotation) // Add the human-node to the graph .addNode("human_node", humanNode) .addEdge("__start__", "human_node") // A checkpointer is required for `interrupt` to work. const checkpointer = new MemorySaver(); const graph = workflow.compile({ checkpointer }); const config = { configurable: { thread_id: "123" } }; // Using stream() to directly surface the `__interrupt__` information. for await (const chunk of await graph.stream( { some_text: "Original text" }, config )) { console.log("Paused state", JSON.stringify(chunk)); } // Resume using Command for await (const chunk of await graph.stream( new Command({ resume: "Edited text" }), config )) { console.log(chunk); } ``` This actually prints ``` Paused state {"__interrupt__":[{"value":{"text_to_revise":"Do you wish to approve ?"},"when":"during","resumable":true,"ns":["human_node:256ce302-2f0b-5ba8-8eba-ec02b2bb7a82"]}]} { human_node: { some_text: 'Edited text' } } ``` But when I use invoke for the execution ``` import { MemorySaver, Annotation, interrupt, Command, StateGraph } from "@langchain/langgraph"; // Define the graph state const StateAnnotation = Annotation.Root({ some_text: Annotation<string>() }); function humanNode(state: typeof StateAnnotation.State) { const value = interrupt( // Any JSON serializable value to surface to the human. // For example, a question or a piece of text or a set of keys in the state { text_to_revise: "Do you wish to approve ?" } ); return { // Update the state with the human's input some_text: value }; } // Build the graph const workflow = new StateGraph(StateAnnotation) // Add the human-node to the graph .addNode("human_node", humanNode) .addEdge("__start__", "human_node") // A checkpointer is required for `interrupt` to work. const checkpointer = new MemorySaver(); const graph = workflow.compile({ checkpointer }); const config = { configurable: { thread_id: "123" } }; const result = await graph.invoke({ some_text: "Original text" },config); console.log("Paused state", JSON.stringify(result)); // Resume using Command for await (const chunk of await graph.stream( new Command({ resume: "Edited text" }), config )) { console.log(chunk); } ``` I am getting only the state where it is paused ``` Paused state {"some_text":"Original text"} { human_node: { some_text: 'Edited text' } } ``` ### Error Message and Stack Trace (if applicable) _No response_ ### Description * Using the streaming it is actually working * But using invoke it is not working ### System Info Linux TS NodeJS 18
yindo closed this issue 2026-02-15 18:15:45 -05:00
Author
Owner

@habberrih commented on GitHub (Jul 24, 2025):

Hi! 👋

You're right — stream() shows the interrupt, but invoke() doesn't. I had the same issue, and this solution worked for me:

const result = await graph.invoke(message, config);

const state = await graph.getState(config.configurable.thread_id);

if (state.tasks[0]?.interrupts?.[0]) {
  return state.tasks[0].interrupts[0].value;
}

This lets you get the value passed to interrupt.
Hope it helps you too!

@habberrih commented on GitHub (Jul 24, 2025): Hi! 👋 You're right — `stream()` shows the interrupt, but `invoke()` doesn't. I had the same issue, and this solution worked for me: ```ts const result = await graph.invoke(message, config); const state = await graph.getState(config.configurable.thread_id); if (state.tasks[0]?.interrupts?.[0]) { return state.tasks[0].interrupts[0].value; } ``` This lets you get the value passed to interrupt. Hope it helps you too!
Author
Owner

@dqbd commented on GitHub (Sep 9, 2025):

Hello! Interrupts should be available in invoke as well since 0.3.x.

@dqbd commented on GitHub (Sep 9, 2025): Hello! Interrupts should be available in `invoke` as well since 0.3.x.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langchain-ai/langgraphjs#307