Skip to content

fix(langgraph): stop reporting answered interrupts in getState - #3113

Open
Mihir Inamdar (inamdarmihir) wants to merge 1 commit into
langchain-ai:mainfrom
inamdarmihir:fix/getstate-answered-interrupts
Open

Mihir Inamdar (inamdarmihir) wants to merge 1 commit into
langchain-ai:mainfrom
inamdarmihir:fix/getstate-answered-interrupts

Conversation

@inamdarmihir

Copy link
Copy Markdown

Fixes #3068

Problem

Two parallel nodes call interrupt(). Resuming one of them with Command({ resume: { [id]: value } }) writes its answer, and the invoke() result lists only the other interrupt as pending. getState() still lists both, so an application that reads pending interrupts from the state (for example after a restart) asks the answered question again.

The snapshot read the recorded INTERRUPT write of every task, finished or not. The finished task was already left out of next, so its answered question showed up as pending with no task left to run.

Change

  • New finishedTaskIds(pendingWrites) in pregel/debug.ts: tasks that wrote output. Errors, interrupts, scheduling markers and a bare resume value do not count, because a resumed task may pause again at its next interrupt().
  • tasksWithWrites takes an optional set of finished tasks and reports no interrupts for them, so their result is returned instead.
  • _prepareStateSnapshot passes the set only when it applies pending writes, which is the latest-state read (getState() without a checkpoint_id). History and explicit-checkpoint reads show the interrupts as recorded, as before.
  • Patch changeset for @langchain/langgraph.

Scope

The Python fix (langchain-ai/langgraph#9103) is wider: it also records NO_WRITES when a resumed task finishes without output, and makes Command(resume=value) without an id raise when several interrupts are pending. This PR does only the getState() part. A task that was resumed and finished without writing anything still shows its answered interrupt, and I did not change the resume-by-id behavior. Happy to follow up on either if you want them.

Tests

src/tests/state_pending_interrupts.test.ts:

  • after a partial resume, getState() lists only the pending interrupt, next and tasks agree, and the finished task shows its result
  • after every interrupt is answered, nothing is pending
  • a read pinned to an earlier checkpoint still shows the recorded interrupts
  • a task resumed but paused again at its next interrupt keeps that interrupt

Two of the four fail on the old code, and all four pass now. libs/langgraph-core: 93 files, 2041 tests pass. tsc and oxfmt --check are clean for the files I changed.

Authored by Mihir

Resuming one of several parallel interrupted tasks by interrupt id wrote
its answer and the invoke result listed only the other interrupt, but
getState() kept listing both: the snapshot read the recorded INTERRUPT
write of every task, finished or not. The finished task was already
left out of `next`, so its answered question appeared pending with no
task to run.

In the latest state, drop the interrupts of tasks that wrote output, so
the task reports its result instead. A resume value alone does not mark a
task finished, because it may pause again at its next interrupt. History
and explicit checkpoint reads keep showing the interrupts as recorded.

Fixes langchain-ai#3068

Authored by Mihir
@changeset-bot

changeset-bot Bot commented Oct 25, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: c66ae6d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@langchain/langgraph Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Oct 25, 2026

Copy link
Copy Markdown

Open in StackBlitz

@langchain/langgraph-checkpoint

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-checkpoint@3113

@langchain/langgraph-checkpoint-mongodb

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-checkpoint-mongodb@3113

@langchain/langgraph-checkpoint-postgres

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-checkpoint-postgres@3113

@langchain/langgraph-checkpoint-redis

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-checkpoint-redis@3113

@langchain/langgraph-checkpoint-sqlite

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-checkpoint-sqlite@3113

@langchain/langgraph-checkpoint-validation

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-checkpoint-validation@3113

create-langgraph

npm i https://pkg.pr.new/langchain-ai/langgraphjs/create-langgraph@3113

@langchain/langgraph-api

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-api@3113

@langchain/langgraph-cli

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-cli@3113

@langchain/langgraph

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph@3113

@langchain/langgraph-cua

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-cua@3113

@langchain/langgraph-supervisor

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-supervisor@3113

@langchain/langgraph-swarm

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-swarm@3113

@langchain/langgraph-ui

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-ui@3113

@langchain/langgraph-sdk

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-sdk@3113

@langchain/angular

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/angular@3113

@langchain/react

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/react@3113

@langchain/svelte

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/svelte@3113

@langchain/vue

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/vue@3113

commit: c66ae6d

Miku_Ht (idealzxz) added a commit to idealzxz/langgraphjs that referenced this pull request Oct 27, 2026
Hide completed-task interrupts only in latest state, keep successive
interrupts pending, and persist NO_WRITES for resumed tasks without output.

Related: langchain-ai#3068, langchain-ai#3113
Prepared with AI assistance.
@idealzxz

Copy link
Copy Markdown

The sdk-vue failure appears to be a pre-existing test race: errorAgent can echo the submitted message before its node throws, making the correct optimistic status sent, while the test always expects failed. The separate fix (#3134) makes dispatch fail before any echo, as the React test already does, and adds deterministic tests for both event orders. The SDK stream suite passes locally (360 tests), along with SDK/Vue type checks and lint. Browser CI still needs to confirm the fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

getState() keeps listing an answered interrupt after a partial resume

2 participants