Confirm this is an issue with the Python library and not an underlying OpenAI API
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.
Confirm this is an issue with the Python library and not an underlying OpenAI API
Describe the bug
client.skills.create(files=("skill.zip", zip_bytes))silently loses the file and constructs anapplication/jsonrequest 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 popsfilesbefore 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
Actual: the first request reports
application/json False; the second reportsmultipart/form-data; boundary=... True.Expected: both requests include the zip in multipart data. The single-file field is
files, while the list form usesfiles[].OS
macOS 26.6.2 ARM64.
Python version
Python 3.13.15.
Library version
Current
mainsource reportingopenai 3.14.1, loaded viaPYTHONPATH=src; httpx2 2.12.0, Pydantic 2.13.5.