openai / openai/openai-python

Skills single-file ZIP uploads are dropped during file extraction

Open
#3,874 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
31.6k
Forks
5.7k
Avg merge
1d 6h
Merged PRs (30d)
96

Description

Confirm this is an issue with the Python library and not an underlying OpenAI API
  • This is an issue with the Python library.
Describe the bug

client.skills.create(files=("skill.zip", zip_bytes)) silently loses the file and constructs an application/json request with an empty body object. Wrapping the same file tuple in a list correctly produces multipart data.

The Skills create contract accepts either multiple files or a single zip. The SDK tries extraction paths [["files", "<array>"], ["files"]; the array path pops files before noticing that a single file is not a list. The fallback then cannot find it. The async client behaves the same way.

To Reproduce

Run the following against the current Python SDK checkout. It generates a zip in memory and uses MockTransport to inspect the actual public-client request; no API key or live service request is needed.

Code snippets
import io
import zipfile
import httpx2
from openai import OpenAI

buffer = io.BytesIO()
with zipfile.ZipFile(buffer, "w") as archive:
    archive.writestr("SKILL.md", "---\nname: example\ndescription: Test skill\n---\n# Example\n")
zip_bytes = buffer.getvalue()

def inspect_request(request):
    print(request.headers["content-type"], zip_bytes in request.content)
    return httpx2.Response(200, json={})  # Local response fixture only.

with OpenAI(
    api_key="fake-key",
    base_url="https://example.test",
    http_client=httpx2.Client(transport=httpx2.MockTransport(inspect_request)),
) as client:
    single = ("skill.zip", zip_bytes)
    client.skills.with_raw_response.create(files=single)
    client.skills.with_raw_response.create(files=[single])

Actual: the first request reports application/json False; the second reports multipart/form-data; boundary=... True.

Expected: both requests include the zip in multipart data. The single-file field is files, while the list form uses files[].

OS

macOS 26.6.2 ARM64.

Python version

Python 3.13.15.

Library version

Current main source reporting openai 3.14.1, loaded via PYTHONPATH=src; httpx2 2.12.0, Pydantic 2.13.5.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at the public client entry point, client.skills.with_raw_response.create, and reproduce the behavior with httpx2.MockTransport using both the single tuple and list forms. Trace the extraction paths for ["files", ""] and ["files"] in the request-building code, including the async client. Done means both forms preserve the ZIP in multipart data, with tests covering the single-file and list cases.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
api
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.