langchain-ai/deepagents · error · ValueError

Auto mode rejects action batches with duplicate tool-call ID

Error message

Auto mode rejects action batches with duplicate tool-call IDs

What it means

Raised by `_validate_unique_tool_call_ids` when a model proposes an action batch containing two or more tool calls with the same `id`. Auto mode needs unique IDs to correlate each proposed action with its own human decision and result message, so it rejects the whole batch.

Source

Thrown at libs/code/deepagents_code/auto_mode.py:1654

    Returns:
        Valid identifier used for plans and decisions.

    Raises:
        ValueError: If the model omitted a stable identifier.
    """
    value = call.get("id")
    if not isinstance(value, str) or not value:
        msg = "Auto mode requires every proposed tool call to have an ID"
        raise ValueError(msg)
    return value


def _validate_unique_tool_call_ids(calls: Sequence[ToolCall]) -> None:
    ids = [_tool_call_id(call) for call in calls]
    if len(ids) != len(set(ids)):
        msg = "Auto mode rejects action batches with duplicate tool-call IDs"
        raise ValueError(msg)


def _batch_id(calls: Sequence[ToolCall]) -> str:
    encoded = "\0".join(_tool_call_id(call) for call in calls).encode("utf-8")
    return sha256(encoded).hexdigest()


def _review_tool_call_ids(
    raw_plan: object,
    valid_tool_call_ids: Collection[str],
) -> list[str]:
    """Return the reviewed tool-call IDs a checkpointed plan still covers.

    These IDs only pause and resume tool rows in the client, so a malformed
    value degrades instead of invalidating the plan that carries it: rejecting
    the plan would discard the classifier's authorization decisions over
    presentation metadata. Drop anything the current message cannot key, and
    drop repeats — the client rejects a duplicated ID and falls back to

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Regenerate the request — transient model glitches usually clear on retry; consider a stronger model if it recurs
  2. Ensure any middleware that clones or retries tool calls assigns a fresh unique `id` to the copy
  3. Fix test fixtures by giving each constructed call a distinct id (e.g. `call_1`, `call_2`)
  4. If a provider integration systematically duplicates ids, upgrade or report it against the integration

Example fix

// before
[{"id": "call_1", "name": "read", "args": {"p": "a"}},
 {"id": "call_1", "name": "read", "args": {"p": "b"}}]

// after
[{"id": "call_1", "name": "read", "args": {"p": "a"}},
 {"id": "call_2", "name": "read", "args": {"p": "b"}}]
Defensive patterns

Strategy: validation

Validate before calling

from collections.abc import Sequence

def ids_are_unique(calls: Sequence[dict]) -> bool:
    ids = [c.get("id") for c in calls]
    return len(ids) == len(set(ids))

Type guard

def has_unique_ids(calls: Sequence[dict]) -> bool:
    return all(isinstance(c.get("id"), str) for c in calls) and len({c["id"] for c in calls}) == len(calls)

Try / catch

try:
    result = agent.invoke(input, config)
except ValueError as exc:
    if "duplicate tool-call IDs" in str(exc):
        retry_request_or_fix_synthesizing_middleware()
    else:
        raise

Prevention

When it happens

Trigger: A model response (or synthesized message) includes `tool_calls` where duplicate `id` values appear — e.g. a buggy model echoing the same id for parallel calls, a provider streaming bug, or test harness code duplicating a call dict.

Common situations: Faulty or quantized local models that emit parallel calls with identical ids; provider/proxy bugs collapsing parallel tool-call ids during streaming; middleware that clones a tool call (e.g. to retry) without minting a new id; hand-built test fixtures with copy-pasted call dicts.

Related errors


AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29). Data as JSON: /api/errors/73302e1998d7bad7. Report an issue: GitHub.