{"record":{"id":"13655f58c2d17023","repo":"openai/openai-python","slug":"raw-multipart-alternative-must-be-a-string","errorCode":null,"errorMessage":"Raw multipart alternative must be a string","messagePattern":"Raw multipart alternative must be a string","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/openai/_multipart.py","lineNumber":31,"sourceCode":"    extra_body: Body | None,\n    encodings: Mapping[str, tuple[str, bool]],\n    raw_body_field: str | None = None,\n    existing_files: RequestFiles | None = None,\n) -> tuple[dict[str, object] | None, RequestFiles | None, bytes | None, str]:\n    \"\"\"Prepare explicitly encoded form fields without flattening their JSON contents.\"\"\"\n    if not isinstance(body, Mapping):\n        raise TypeError(\"Multipart request body must be a mapping\")\n    if extra_body is not None and not isinstance(extra_body, Mapping):\n        raise TypeError(\"Multipart extra_body must be a mapping\")\n    original = cast(Mapping[str, object], body)\n    overrides = cast(Mapping[str, object], extra_body or {})\n    merged = {key: value for key, value in {**original, **overrides}.items() if not isinstance(value, (Omit, NotGiven))}\n    # A raw request alternative is safe only when there is no other payload to lose.\n    # Explicit null remains a JSON part; only an omitted field selects the raw body.\n    if not existing_files and raw_body_field is not None and set(merged) == {raw_body_field}:\n        value = merged[raw_body_field]\n        if not isinstance(value, str):\n            raise TypeError(\"Raw multipart alternative must be a string\")\n        return None, None, value.encode(\"utf-8\"), encodings[raw_body_field][0]\n\n    files: list[tuple[str, FileTypes]] = list(\n        existing_files.items() if isinstance(existing_files, Mapping) else (existing_files or [])\n    )\n    for name, (content_type, as_json) in encodings.items():\n        if name not in merged:\n            continue\n        value = merged.pop(name)\n        if as_json:\n            data = openapi_dumps(value)\n        else:\n            if not isinstance(value, str):\n                raise TypeError(f\"Multipart field {name!r} must be a string\")\n            data = value.encode(\"utf-8\")\n        files.append((name, (None, data, content_type)))\n    return merged or None, files, None, \"multipart/form-data\"\n","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/openai/openai-python/blob/9917c6e28e66e90e1227b3d223c06a8c5441515a/src/openai/_multipart.py#L13-L49","documentation":"When a multipart request consists solely of the raw-body alternative field, the SDK sends it verbatim as the entire request body, which requires a string it can UTF-8 encode. Any other type (int, dict, bytes) cannot be sent as the raw alternative and raises TypeError.","triggerScenarios":"A multipart call where every other field is NotGiven/Omit and the raw_body_field value is not a str — e.g. passing a dict or pre-encoded bytes as the raw alternative.","commonSituations":"Using the raw-alternative escape hatch (e.g. sending a pre-rendered form or template string) but passing structured data instead of its serialized string form.","solutions":["Serialize the raw body to a string first (e.g. json.dumps(...) or the required text format) before passing it","If you intend normal multipart encoding, ensure other fields are present so the raw-alternative path isn't selected","Double-check you're populating the designated raw-body field with text"],"exampleFix":"// before\nclient.resources.create(raw='{\"a\": 1}')  # passing a dict\nclient.resources.create(raw={'a': 1})\n// after\nclient.resources.create(raw=json.dumps({'a': 1}))","handlingStrategy":"type-guard","validationCode":"if raw_body is not None and not isinstance(raw_body, str):\n    raw_body = json.dumps(raw_body)","typeGuard":"from typing import TypeGuard\n\ndef is_raw_alternative(value: object) -> TypeGuard[str]:\n    return isinstance(value, str)","tryCatchPattern":null,"preventionTips":["Serialize raw-body alternatives to a string yourself before calling the API","Don't put structured data into the raw-body field"],"tags":["python","multipart","raw-body","type-error"],"backgroundTag":"raw-request-body-must-be-string","analyzedSha":"9917c6e28e66e90e1227b3d223c06a8c5441515a","analyzedAt":"2026-08-28T11:46:34.183Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}