openai/openai-python · error · TypeError
Multipart request body must be a mapping
Error message
Multipart request body must be a mapping
What it means
encode_multipart() requires the request body to be a Mapping (dict-like) so it can merge, filter NotGiven/Omit values, and encode each field as a form part. A non-mapping body (e.g. a string, bytes, or list) cannot be processed this way, so a TypeError is raised immediately.
Source
Thrown at src/openai/_multipart.py:20
from __future__ import annotations
from typing import Mapping, cast
from ._types import Body, Omit, NotGiven, FileTypes, RequestFiles
from ._utils._json import openapi_dumps
def encode_multipart(
body: object,
extra_body: Body | None,
encodings: Mapping[str, tuple[str, bool]],
raw_body_field: str | None = None,
existing_files: RequestFiles | None = None,
) -> tuple[dict[str, object] | None, RequestFiles | None, bytes | None, str]:
"""Prepare explicitly encoded form fields without flattening their JSON contents."""
if not isinstance(body, Mapping):
raise TypeError("Multipart request body must be a mapping")
if extra_body is not None and not isinstance(extra_body, Mapping):
raise TypeError("Multipart extra_body must be a mapping")
original = cast(Mapping[str, object], body)
overrides = cast(Mapping[str, object], extra_body or {})
merged = {key: value for key, value in {**original, **overrides}.items() if not isinstance(value, (Omit, NotGiven))}
# A raw request alternative is safe only when there is no other payload to lose.
# Explicit null remains a JSON part; only an omitted field selects the raw body.
if not existing_files and raw_body_field is not None and set(merged) == {raw_body_field}:
value = merged[raw_body_field]
if not isinstance(value, str):
raise TypeError("Raw multipart alternative must be a string")
return None, None, value.encode("utf-8"), encodings[raw_body_field][0]
files: list[tuple[str, FileTypes]] = list(
existing_files.items() if isinstance(existing_files, Mapping) else (existing_files or [])
)
for name, (content_type, as_json) in encodings.items():
if name not in merged:View on GitHub (pinned to 9917c6e28e)
Solutions
- Pass the body as a dict/Mapping of field names to values
- If you have serialized JSON, parse it back to a dict before the call, or use a JSON (non-multipart) endpoint
- For raw string alternatives, use the documented raw-body field mechanism rather than replacing the whole body
Example fix
// before
client.files.create(file=open('f.txt','rb'), purpose='assistants', body='raw')
// after
client.files.create(file=open('f.txt','rb'), purpose='assistants') Defensive patterns
Strategy: type-guard
Validate before calling
from collections.abc import Mapping assert isinstance(body, Mapping), 'multipart body must be a dict'
Type guard
from collections.abc import Mapping
from typing import TypeGuard
def is_multipart_body(value: object) -> TypeGuard[Mapping[str, object]]:
return isinstance(value, Mapping) Prevention
- Always pass multipart bodies as dicts of field->value
- Parse serialized JSON back to a dict before sending
When it happens
Trigger: Calling a multipart endpoint (file upload/transcription) via client.<resource>.create(...) with body as a string/bytes/list, or calling encode_multipart directly with a non-mapping body.
Common situations: Passing a pre-serialized JSON string as the body; custom wrappers that convert the body dict to another type before calling the SDK; calling internal helpers with raw payloads.
Related errors
- Multipart extra_body must be a mapping
- Pagination is only supported with mappings
- No next page expected; please check `.has_next_page()` befor
- max_retries cannot be None. If you want to disable retries,
- Unexpected JSON data type, {type(json_data)}, cannot merge w
AI-assisted analysis of openai/openai-python@9917c6e28e (2026-08-28).
Data as JSON: /api/errors/5cc82be10f25f669.
Report an issue: GitHub.