{"record":{"id":"1ac8664ed91da206","repo":"openai/openai-python","slug":"multipart-field-name-r-must-be-a-string","errorCode":null,"errorMessage":"Multipart field {name!r} must be a string","messagePattern":"Multipart field (.+?) must be a string","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/openai/_multipart.py","lineNumber":45,"sourceCode":"    # 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":27,"sourceCodeEnd":49,"githubUrl":"https://github.com/openai/openai-python/blob/9917c6e28e66e90e1227b3d223c06a8c5441515a/src/openai/_multipart.py#L27-L49","documentation":"Fields listed in the multipart encodings map with as_json=False must be plain strings so they can be UTF-8 encoded as form parts. If such a field holds a non-string (int, dict, list, None), encoding is impossible and TypeError is raised naming the field.","triggerScenarios":"A multipart request where a text-encoded field (declared string in the API schema) receives a non-string value — e.g. passing metadata as a dict to a field the SDK encodes as text, or an int where a string enum is expected.","commonSituations":"Passing numbers/booleans/dicts to string-typed multipart parameters; forgetting that only as_json fields accept structured values.","solutions":["Convert the value to a string before the call (str(value), or json.dumps for structured data if the field accepts JSON text)","Move structured data into a field designed for JSON encoding or into extra_body","Check the endpoint's parameter type and match it"],"exampleFix":"// before\nclient.foo.create(text_field={\"a\": 1})\n# or\nclient.foo.create(text_field=42)\n// after\nclient.foo.create(text_field=json.dumps({\"a\": 1}))\n# or\nclient.foo.create(text_field=\"42\")","handlingStrategy":"type-guard","validationCode":"payload = {k: (v if isinstance(v, str) or k in JSON_FIELDS else json.dumps(v)) for k, v in payload.items()}","typeGuard":"from typing import TypeGuard\n\ndef all_text_fields_str(fields: dict[str, object], text_fields: set[str]) -> TypeGuard[dict[str, str]]:\n    return all(isinstance(fields.get(k), str) for k in text_fields)","tryCatchPattern":null,"preventionTips":["Match each multipart field's value type to the endpoint schema","Coerce numbers/bools to strings before sending text-encoded fields"],"tags":["python","multipart","type-error","form-data"],"backgroundTag":"form-field-type-mismatch","analyzedSha":"9917c6e28e66e90e1227b3d223c06a8c5441515a","analyzedAt":"2026-08-28T11:46:34.183Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}