openai/openai-python · error · TypeError
Invalid `http_client` argument; Expected an instance of `htt
Error message
Invalid `http_client` argument; Expected an instance of `httpx.Client` or `httpx2.Client` but got {type(http_client)} What it means
Raised by sync upload_file_chunked when `file` is bytes and `bytes` (the declared total size) was not given. The chunked upload protocol needs the total size up front to create the upload session, and it cannot be derived from streaming bytes, so the SDK raises TypeError. In practice this fires only when filename was provided but the size is missing.
Source
Thrown at src/openai/_base_client.py:929
# if the user passed in a custom http client with a non-default
# timeout set then we use that timeout.
#
# note: there is an edge case here where the user passes in a client
# where they've explicitly set the timeout to match the default timeout
# as this check is structural, meaning that we'll think they didn't
# pass in a timeout and will ignore it
client_timeout = normalize_httpx_timeout(http_client.timeout) if http_client else None
if http_client and client_timeout != HTTPX_DEFAULT_TIMEOUT:
timeout = client_timeout
else:
timeout = DEFAULT_TIMEOUT
if (
http_client is not None
and not is_httpx2_sync_client(http_client)
and not is_legacy_httpx_sync_client(http_client)
):
raise TypeError(
"Invalid `http_client` argument; Expected an instance of `httpx.Client` or `httpx2.Client` "
f"but got {type(http_client)}"
)
super().__init__(
version=version,
# cast to a valid type because mypy doesn't understand our type narrowing
timeout=cast(Timeout, timeout),
base_url=base_url,
max_retries=max_retries,
custom_query=custom_query,
custom_headers=custom_headers,
_strict_response_validation=_strict_response_validation,
)
self._client = http_client or SyncHttpxClientWrapper(
base_url=base_url,
# cast to a valid type because mypy doesn't understand our type narrowing
timeout=cast(Timeout, timeout),View on GitHub (pinned to 9917c6e28e)
Solutions
- Prefer the public client.files.create / upload helper over manual chunked calls so sizes are handled for you
- If calling upload_file_chunked directly, always pass bytes=len(data) alongside filename
- Validate size is a positive int before uploading
Example fix
# before client.beta.uploads.upload_file_chunked(data, purpose='assistants', filename='a.bin') # after client.uploads.upload_file_chunked(data, bytes=len(data), purpose='assistants', filename='a.bin')
Defensive patterns
Strategy: validation
Validate before calling
if isinstance(data, bytes):
assert filename, 'filename required for bytes uploads'
assert isinstance(total_bytes, int) and total_bytes > 0, 'bytes (size) required' Type guard
def chunked_args_ready(data: object, filename: object, size: object) -> bool:
return (not isinstance(data, (bytes, bytearray))) or (bool(filename) and isinstance(size, int) and size > 0) Prevention
- Prefer high-level upload helpers over manual chunked calls
- Compute bytes=len(data) once and reuse it
- Type-check size as int; the server also validates totals
When it happens
Trigger: Calling upload_file_chunked with in-memory bytes, a filename, but omitting the bytes= (size) argument.
Common situations: Hand-rolling the multipart/chunked flow against uploads.create + parts.create + complete instead of using the helper, or partially migrating old code that passed only the file.
Related errors
- Passing both `files` and `content` is not supported
- Passing both `body` and `content` is not supported
- You tried to pass a `BaseModel` class to `chat.completions.c
- Pagination is only supported with mappings
- No next page expected; please check `.has_next_page()` befor
AI-assisted analysis of openai/openai-python@9917c6e28e (2026-08-28).
Data as JSON: /api/errors/1ed0258012b1c570.
Report an issue: GitHub.