Skip to content

[Bug]: Duplicate tool call IDs (e.g., edit:22) trigger HTTP 400 in OpenAI-compatible APIs #40897

@caoyacheng

Description

@caoyacheng

Bug type

Regression (worked before, now fails)

Summary

Requests are failing with an HTTP 400 Bad Request error because they contain duplicate tool_call_id values (e.g., edit:22). OpenAI and compatible backends (e.g., OpenAI Responses) require every tool call ID within a single request to be unique. Once a duplicate ID is detected, the server returns a 400 error.

Root Cause
The issue stems from the ID format toolName:index, commonly generated by upstream clients like Cursor or Codex.

Intra-Message Duplication: The current normalizeToolCallIdsInMessage logic only handles filling empty IDs (to call_auto_N) or trimming whitespace. It does not deduplicate identical IDs within a single assistant message (e.g., two blocks both labeled edit:22).

Historical Duplication: Due to the current transcript-policy (specifically the test "does not sanitize tool call ids for openai-responses"), duplicate IDs from previous conversation turns are preserved and sent in subsequent requests, triggering the server's uniqueness check.

Steps to reproduce

1.Use a client or model that generates IDs in the format toolName:index.

2.Trigger multiple tool calls in a single turn that result in the same ID (e.g., two edit:22 calls in one message).

3.OR, engage in a multi-turn conversation where a previous tool_call_id from the history is reused in the current request.

4.The backend returns a 400 error.

Expected behavior

The system should ensure that all tool_call_id values sent in a request are unique. This should be handled by the normalization logic to either re-index duplicates or ensure they are sanitized before being sent to the API.

Actual behavior

Duplicate IDs (like edit:22) are sent as-is, causing the API to reject the entire request.

OpenClaw version

2026.3.7

Operating system

macOS 15.6.1

Install method

No response

Logs, screenshots, and evidence

Impact and severity

No response

Additional information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingregressionBehavior that previously worked and now fails

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions