Duplicate item found with id msg_... when submitting tool output (400 invalid_request_error)

I’m integrating OpenAI tool calling in an async app and I’m intermittently hitting this error when submitting the tool output:

Error code: 400
Duplicate item found with id msg_XXXXXXXX.... Remove duplicate items from your input and try again.
(type: invalid_request_error, param: input, code: None)

This seems to occur specifically when the user sends an image file along with a prompt.

Logs show the same user message being handled twice for image+prompt inputs. I suspect this duplication results in repeated msg_... item IDs and triggers the Duplicate item found with id msg_... error during tool output submission.

I’m using tool calling (function tools) and I must submit tool output so the conversation can continue. The failure happens at the step where I submit the tool output / continue the run.

Important: I only submit a single function_call_output item to continue. With text-only messages, the exact same code path works for the rest.

Minimal payload I send to Responses API

[
  {
    "type": "function_call_output",
    "call_id": "call_XXXXXXXXXXXX",
    "output": "<json string>"
  }
]

Minimal snippet

async def submit_output(client, conversation_id, call_id, output):
    return await client.responses.create(
        conversation=conversation_id,
        model="gpt-5.2",
        input=[{
            "type": "function_call_output",
            "call_id": call_id,
            "output": output,
        }],
        stream=True,
    )

Could this be an SDK issue?

Is there a recommended fix pattern in code?

Why would this happen only with image+prompt but not text-only , when I’m “using the same logic”?
Any known bugs where image uploads/attachments cause the user message event to fire twice or lead to duplicated input items?

  • Python SDK: openai==2.17
  • API: Responses API
  • Python 3.11.4
5 Likes

I’have been facing the problem while using responses api. Any official explanation?

This happened a while ago also.

The tool ID is part of functions-wrapped-in-tools (not like you can actually make real tools though). It helps index parallel tool calls back to the order they were emitted.

They should be hashed and unique and take the lifetime of the universe to collide. OpenAI didn’t get the memo, though, and even prior turns could have been given the same ID.

Here, it might be a persistent problem with the Responses API and the models running there that they do not stop generating correctly, and are repeating the same assistant output again…and again. Then the technique for assigning those IDs is sticking them in your stateful storage server-side for a reuse of response ID or conversation ID.

Solution:

  • store:false
  • self-management of conversations and all input
  • rewrite tool IDs with your own unique pairings between call and “tool” role message. Drop duplicates from API fault.
  • avoid issues and upgrade to Chat Completions.

Hi and welcome to the community!

Short version: this is not an image-specific SDK bug. The Duplicate item found with id msg_… error happens when previously returned items (with server-assigned IDs) are accidentally sent again in the continuation request.

A few key points that line up with what you’re seeing:

When you pass conversation=<conversation_id>, the API automatically prepends all existing conversation items before processing your new input.

If your code also re-sends anything that originally came from the model (for example cached response.output, streamed items, or reconstructed messages), those items already have IDs like msg_… Sending those items again causes the same IDs to appear twice in the effective request, which triggers:

400 invalid_request_error` `Duplicate item found with id msg_…

That’s why it looks image-specific in practice. Image + prompt flows tend to be more complex: more streaming events, more intermediate state, more chances to accidentally replay something you didn’t mean to. Text-only paths are simpler and often don’t hit the same code path.

A couple of clarifications based on this:

  • Submitting exactly one function_call_output works fine in conversation mode, including with image + prompt, as long as that really is the only thing in input.
  • Submitting the same tool output twice concurrently does not produce duplicate-item. That fails with conversation_locked instead. So if you’re seeing duplicate-item, it’s almost always duplicated input items, not parallel submits.
  • The SDK isn’t duplicating messages on its own. The duplication happens when previously returned items are unintentionally fed back into input.

The invariant that matters is simple:

When continuing a run with conversation=<conversation_id>, the request must be delta-only.
For tool continuation, input must contain only the single function_call_output, and nothing that came from the model earlier.

Once that’s enforced (no replayed items, no server IDs, exactly-once submission per tool call), the error stops occurring.

2 Likes