2025, Dec 02 07:00

Fix the OpenAI Assistants API 'unexpected keyword file_ids' error: use attachments with file_id

Learn why messages.create rejects file_ids in the OpenAI Assistants API and how to upload files correctly with attachments and file_id for the code interpreter.

Uploading a file to a message in the OpenAI Assistants API can fail with an unexpected keyword error if you pass the wrong parameter. The issue looks trivial, but it blocks the whole run when you try to attach input data for tools like the code interpreter.

Problem in context

The message creation step uses a keyword that the endpoint does not accept. The call throws at runtime and stops the thread flow.

# Create a message with the uploaded file
post = api.beta.threads.messages.create(
    thread_id=dialog.id,
    role="user",
    content="Here is the HTML content for the seminar page.",
    file_ids=[uploaded.id]  # expected to pass the file here
)

When executed, the call fails with:

An error occurred: Messages.create() got an unexpected keyword argument 'file_ids'

What actually goes wrong

The messages.create endpoint does not accept a top-level file_ids argument. Instead, it expects attachments. Inside attachments, each item uses file_id as a field. The similar-looking file_ids exists elsewhere in the Assistants API surface, but there it appears as a field inside a dictionary, not as a direct parameter to message creation. This mismatch is why the call raises an unexpected keyword error.

Working approach and corrected example

Switching to the attachments parameter resolves the problem. Each attachment item includes the file_id and can specify which tools should consume the file.

# Create a new assistant
helper = api.beta.assistants.create(
    name="Seminar HTML to CSV Assistant",
    instructions=instructions,
    model="gpt-4",
    tools=[{"type": "code_interpreter"}],
)

# Create a thread
dialog = api.beta.threads.create()

# Create a message with the uploaded file
post = api.beta.threads.messages.create(
    thread_id=dialog.id,
    role="user",
    content="Here is the HTML content for the seminar page.",
    attachments=[{"file_id": uploaded.id, "tools": [{"type": "code_interpreter"}]}]
)

# Run the assistant
job = api.beta.threads.runs.create(
    thread_id=dialog.id,
    assistant_id=helper.id
)

Why this detail matters

Using attachments ensures the file is correctly bound to the message and made available to the specified tools. This is essential when you need the code interpreter to process an uploaded asset as part of the run, for example to parse HTML or transform data. Passing a wrong parameter at the message layer silently blocks this flow until the error is fixed.

Takeaways

When creating a message in a thread, rely on attachments with file_id rather than a top-level file_ids. Reserve file_ids for the places where it is explicitly accepted inside a dictionary. If in doubt, double-check the CreateMessage reference and, for deeper context, review how attachments are structured and how they relate to tools like the code interpreter. This alignment will save you from runtime surprises and keep your Assistants pipeline moving.