Skip to content

[bug] Subagent 并发 sandbox 工具调用时可能触发 INVALID_CONCURRENT_GRAPH_UPDATE #3628

Description

@aooohan

Before you start

  • I searched existing issues and this is not a duplicate.
  • I can reproduce this on the latest main.

Problem summary

在 subagent 执行过程中,如果同一个 graph step 内有多个 sandbox 工具并发懒初始化 sandbox,LangGraph报错

Affected area(s)

Agents / LangGraph (graph, prompts, langgraph.json)

What happened?

问题描述

在 subagent 执行过程中,如果同一个 graph step 内有多个 sandbox 工具并发懒初始化 sandbox,LangGraph 可能报错:

langgraph.errors.InvalidUpdateError: At key 'sandbox': Can receive only one value per step. Use an Annotated key to handle multiple values.

实际日志示例:

Subagent general-purpose async execution failed
langgraph.errors.InvalidUpdateError: At key 'sandbox': Can receive only one value per step. Use an Annotated key to handle multiple values.

Expected behavior

同一步内多个工具写入相同的 sandbox_id 时,应通过 merge_sandbox 幂等合并,不应失败。
如果写入不同 sandbox_id,则继续由 merge_sandbox 抛出冲突错误。

Steps to reproduce

Relevant logs

-

How are you running DeerFlow?

Docker (make docker-start)

Operating system

Linux

Platform details

No response

Python version

No response

Node.js version

No response

pnpm version

No response

uv version

No response

Git state

No response

Additional context

根因分析

SandboxMiddleware.wrap_tool_call/awrap_tool_call 会在懒初始化 sandbox 后返回:

Command(update={"sandbox": {"sandbox_id": sandbox_id}, "messages": [...]})

当同一个 graph step 内多个 sandbox 工具都懒初始化并写入相同的 sandbox_id 时,理论上应该由 merge_sandbox 幂等合并。

但是 SandboxMiddlewareState 自己声明了 sandbox 字段,且没有 Annotated[..., merge_sandbox]。LangGraph 合并 middleware state schema 时,这个局部 schema 可能覆盖 ThreadState.sandbox 上的 reducer,导致 sandbox 退化成 LastValue channel,于是同一步多个写入触发:

Can receive only one value per step

建议修复

SandboxMiddlewareState.sandbox 保留和 ThreadState.sandbox 一致的 reducer:

from typing import Annotated, NotRequired, override

from deerflow.agents.thread_state import SandboxState, ThreadDataState, merge_sandbox

class SandboxMiddlewareState(AgentState):
    sandbox: Annotated[NotRequired[SandboxState | None], merge_sandbox]
    thread_data: NotRequired[ThreadDataState | None]

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingneeds-triageAwaiting maintainer triage

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions