[GH-ISSUE #130] Subagent interruptOn causes TypeError in LangGraph runner #31

Closed
opened 2026-02-16 06:16:55 -05:00 by yindo · 5 comments
Owner

Originally created by @zhdanovartur on GitHub (Jan 21, 2026).
Original GitHub issue: https://github.com/langchain-ai/deepagentsjs/issues/130

Description

When using interruptOn configuration inside a subagent definition in createDeepAgent, the interrupt is not properly propagated to the parent graph, causing a TypeError in the LangGraph runner.

Error

TypeError: Cannot read properties of undefined (reading 'length')
    at PregelRunner._commit (node_modules/@langchain/langgraph/src/pregel/runner.ts:362:30)
    at PregelRunner.tick (node_modules/@langchain/langgraph/src/pregel/runner.ts:139:12)

Environment

  • deepagents: 1.5.0
  • @langchain/langgraph: 1.1.0
  • langchain: 1.2.10
  • Node.js: v22.x

Reproduction

Minimal example

import {createDeepAgent, type SubAgent} from "deepagents";
import {tool} from "langchain";
import {MemorySaver} from "@langchain/langgraph";
import {ChatOpenAI} from "@langchain/openai";
import {z} from "zod";
import "dotenv/config";

const sensitiveTool = tool(
    async ({param}: { param: string }) => ({result: param}),
    {
        name: "sensitive_tool",
        description: "A tool that requires human approval",
        schema: z.object({
            param: z.string().describe("Some parameter"),
        }),
    }
);

const subagent: SubAgent = {
    name: "worker-agent",
    description: "Agent that performs sensitive operations",
    systemPrompt: "You perform sensitive operations using sensitive_tool.",
    tools: [sensitiveTool],
    model: new ChatOpenAI({model: "gpt-4.1", temperature: 0}),
    interruptOn: {
        sensitive_tool: true,
    },
};

const agent = createDeepAgent({
    model: new ChatOpenAI({model: "gpt-4.1", temperature: 0}),
    tools: [],
    systemPrompt: "Delegate sensitive operations to worker-agent.",
    checkpointer: new MemorySaver(),
    subagents: [subagent],
});

(async () => {
    const result = await agent.invoke(
        {messages: [{role: "user", content: "Perform sensitive operation with param=test"}]},
        {configurable: {thread_id: "test"}}
    );
    console.log(result);
})();

Expected behavior

The interrupt from the subagent should propagate to the parent graph, and the result should contain __interrupt__ with the pending tool call for approval.

Actual behavior

The application crashes with TypeError: Cannot read properties of undefined (reading 'length') at PregelRunner._commit.

This interrupts before the subagent is called, but does not allow interrupting specific tools inside the subagent.

However, if the same tool is added to the parent (root) agent, the interrupt works, but the tool is then executed by the parent agent instead of the subagent. This makes it impossible for the subagent to observe, post-process, or reason about the tool result, since the execution no longer happens in the subagent’s context.

Originally created by @zhdanovartur on GitHub (Jan 21, 2026). Original GitHub issue: https://github.com/langchain-ai/deepagentsjs/issues/130 ## Description When using `interruptOn` configuration inside a subagent definition in `createDeepAgent`, the interrupt is not properly propagated to the parent graph, causing a TypeError in the LangGraph runner. ## Error ``` TypeError: Cannot read properties of undefined (reading 'length') at PregelRunner._commit (node_modules/@langchain/langgraph/src/pregel/runner.ts:362:30) at PregelRunner.tick (node_modules/@langchain/langgraph/src/pregel/runner.ts:139:12) ``` ## Environment - `deepagents`: 1.5.0 - `@langchain/langgraph`: 1.1.0 - `langchain`: 1.2.10 - Node.js: v22.x ## Reproduction ### Minimal example ```typescript import {createDeepAgent, type SubAgent} from "deepagents"; import {tool} from "langchain"; import {MemorySaver} from "@langchain/langgraph"; import {ChatOpenAI} from "@langchain/openai"; import {z} from "zod"; import "dotenv/config"; const sensitiveTool = tool( async ({param}: { param: string }) => ({result: param}), { name: "sensitive_tool", description: "A tool that requires human approval", schema: z.object({ param: z.string().describe("Some parameter"), }), } ); const subagent: SubAgent = { name: "worker-agent", description: "Agent that performs sensitive operations", systemPrompt: "You perform sensitive operations using sensitive_tool.", tools: [sensitiveTool], model: new ChatOpenAI({model: "gpt-4.1", temperature: 0}), interruptOn: { sensitive_tool: true, }, }; const agent = createDeepAgent({ model: new ChatOpenAI({model: "gpt-4.1", temperature: 0}), tools: [], systemPrompt: "Delegate sensitive operations to worker-agent.", checkpointer: new MemorySaver(), subagents: [subagent], }); (async () => { const result = await agent.invoke( {messages: [{role: "user", content: "Perform sensitive operation with param=test"}]}, {configurable: {thread_id: "test"}} ); console.log(result); })(); ``` ## Expected behavior The interrupt from the subagent should propagate to the parent graph, and the result should contain `__interrupt__` with the pending tool call for approval. ## Actual behavior The application crashes with `TypeError: Cannot read properties of undefined (reading 'length')` at `PregelRunner._commit`. This interrupts before the subagent is called, but does not allow interrupting specific tools **inside** the subagent. However, if the same tool is added to the parent (root) agent, the interrupt works, but the tool is then executed by the parent agent instead of the subagent. This makes it impossible for the subagent to observe, post-process, or reason about the tool result, since the execution no longer happens in the subagent’s context.
yindo closed this issue 2026-02-16 06:16:55 -05:00
Author
Owner

@yevhenii-bruchkovskyi-zelh commented on GitHub (Jan 23, 2026):

have a same

@yevhenii-bruchkovskyi-zelh commented on GitHub (Jan 23, 2026): have a same
Author
Owner

@christian-bromann commented on GitHub (Jan 23, 2026):

@zhdanovartur @yevhenii-bruchkovskyi-zelh could you please update to deepagents@v1.5.1? We have pushed a fix for this.

@christian-bromann commented on GitHub (Jan 23, 2026): @zhdanovartur @yevhenii-bruchkovskyi-zelh could you please update to `deepagents@v1.5.1`? We have pushed a fix for this.
Author
Owner

@zhdanovartur commented on GitHub (Jan 23, 2026):

@christian-bromann

could you please update to deepagents@v1.5.1? We have pushed a fix for this.

Checked. It got better. However, if the tool exists both in the main agent and in the sub-agent, there will be no interrupt, even if the sub-agent is configured to interrupt.

But, I'm not sure if my expectation is correct and such a use case exists. Theoretically - yes.

import { createDeepAgent, type SubAgent } from "deepagents";
import { tool } from "langchain";
import { MemorySaver } from "@langchain/langgraph";
import { ChatOpenAI } from "@langchain/openai";
import { z } from "zod";
import "dotenv/config";

const sensitiveTool = tool(
  async ({ param }: { param: string }) => ({ result: param }),
  {
    name: "sensitive_tool",
    description: "A tool that requires human approval",
    schema: z.object({
      param: z.string().describe("Some parameter"),
    }),
  },
);

const subagent: SubAgent = {
  name: "worker-agent",
  description: "Agent that performs sensitive operations",
  systemPrompt: "You perform sensitive operations using sensitive_tool.",
  tools: [sensitiveTool],
  model: new ChatOpenAI({ model: "gpt-4.1", temperature: 0 }),
  interruptOn: {
    [sensitiveTool.name]: true, // <---------- Doesn't work
  },
};

const agent = createDeepAgent({
  model: new ChatOpenAI({ model: "gpt-4.1", temperature: 0 }),
  tools: [sensitiveTool],
  systemPrompt: "Delegate sensitive operations to worker-agent.",
  checkpointer: new MemorySaver(),
  subagents: [subagent],
});

(async () => {
  const result = await agent.invoke(
    {
      messages: [
        {
          role: "user",
          content: "Perform sensitive operation with param=test",
        },
      ],
    },
    { configurable: { thread_id: "test" } },
  );
  console.log(result);
})();
@zhdanovartur commented on GitHub (Jan 23, 2026): @christian-bromann > could you please update to `deepagents@v1.5.1`? We have pushed a fix for this. Checked. It got better. However, if the tool exists both in the main agent and in the sub-agent, there will be no interrupt, even if the sub-agent is configured to interrupt. But, I'm not sure if my expectation is correct and such a use case exists. Theoretically - yes. ```typescript import { createDeepAgent, type SubAgent } from "deepagents"; import { tool } from "langchain"; import { MemorySaver } from "@langchain/langgraph"; import { ChatOpenAI } from "@langchain/openai"; import { z } from "zod"; import "dotenv/config"; const sensitiveTool = tool( async ({ param }: { param: string }) => ({ result: param }), { name: "sensitive_tool", description: "A tool that requires human approval", schema: z.object({ param: z.string().describe("Some parameter"), }), }, ); const subagent: SubAgent = { name: "worker-agent", description: "Agent that performs sensitive operations", systemPrompt: "You perform sensitive operations using sensitive_tool.", tools: [sensitiveTool], model: new ChatOpenAI({ model: "gpt-4.1", temperature: 0 }), interruptOn: { [sensitiveTool.name]: true, // <---------- Doesn't work }, }; const agent = createDeepAgent({ model: new ChatOpenAI({ model: "gpt-4.1", temperature: 0 }), tools: [sensitiveTool], systemPrompt: "Delegate sensitive operations to worker-agent.", checkpointer: new MemorySaver(), subagents: [subagent], }); (async () => { const result = await agent.invoke( { messages: [ { role: "user", content: "Perform sensitive operation with param=test", }, ], }, { configurable: { thread_id: "test" } }, ); console.log(result); })(); ```
Author
Owner

@christian-bromann commented on GitHub (Jan 23, 2026):

@zhdanovartur I think what happens here is:

  1. LLM receives request "Perform sensitive operation with param=test"
  2. LLM sees it has sensitive_tool available directly
  3. LLM calls sensitive_tool directly (NOT via the task tool)
  4. Main agent processes the tool call - no HITL middleware on main agent
  5. Tool executes without interruption

So the interrupt you define in the sub agent doesn't change anything because the subagent never calls the tool.

@christian-bromann commented on GitHub (Jan 23, 2026): @zhdanovartur I think what happens here is: 1. LLM receives request "Perform sensitive operation with param=test" 1. LLM sees it has sensitive_tool available directly 1. LLM calls sensitive_tool directly (NOT via the task tool) 1. Main agent processes the tool call - no HITL middleware on main agent 1. Tool executes without interruption So the interrupt you define in the sub agent doesn't change anything because the subagent never calls the tool.
Author
Owner

@zhdanovartur commented on GitHub (Jan 26, 2026):

@christian-bromann Ah, I see. Thanks!

@zhdanovartur commented on GitHub (Jan 26, 2026): @christian-bromann Ah, I see. Thanks!
yindo changed title from Subagent interruptOn causes TypeError in LangGraph runner to [GH-ISSUE #130] Subagent interruptOn causes TypeError in LangGraph runner 2026-06-05 17:21:05 -04:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langchain-ai/deepagentsjs#31