{"record":{"id":"1379bd6dd2294418","repo":"aio-libs/aiohttp","slug":"only-io-iobase-multidict-and-name-file-pairs-a","errorCode":null,"errorMessage":"Only io.IOBase, multidict and (name, file) pairs allowed, use .add_field() for passing more complex parameters, got {rec!r}","messagePattern":"Only io\\.IOBase, multidict and \\(name, file\\) pairs allowed, use \\.add_field\\(\\) for passing more complex parameters, got (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"aiohttp/formdata.py","lineNumber":101,"sourceCode":"    def add_fields(self, *fields: Any) -> None:\n        to_add: deque[Any] = deque(fields)\n\n        while to_add:\n            rec = to_add.popleft()\n\n            if isinstance(rec, io.IOBase):\n                k = guess_filename(rec, \"unknown\")\n                self.add_field(k, rec)  # type: ignore[arg-type]\n\n            elif isinstance(rec, (MultiDictProxy, MultiDict)):\n                to_add.extend(rec.items())\n\n            elif isinstance(rec, (list, tuple)) and len(rec) == 2:\n                k, fp = rec\n                self.add_field(k, fp)\n\n            else:\n                raise TypeError(\n                    \"Only io.IOBase, multidict and (name, file) \"\n                    \"pairs allowed, use .add_field() for passing \"\n                    f\"more complex parameters, got {rec!r}\"\n                )\n\n    def _gen_form_urlencoded(self) -> payload.BytesPayload:\n        # form data (x-www-form-urlencoded)\n        data = []\n        for type_options, _, value in self._fields:\n            if not isinstance(value, str):\n                raise TypeError(f\"expected str, got {value!r}\")\n            data.append((type_options[\"name\"], value))\n\n        charset = self._charset if self._charset is not None else \"utf-8\"\n\n        if charset == \"utf-8\":\n            content_type = \"application/x-www-form-urlencoded\"\n        else:","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/formdata.py#L83-L119","documentation":"FormData.add_fields (plural) raises TypeError when it encounters a record that is not an io.IOBase instance, a MultiDict/MultiDictProxy, or a 2-element list/tuple of (name, value). The variadic add_fields method iterates records and dispatches them — anything that does not match the three accepted shapes is rejected.","triggerScenarios":"Passing a plain dict to add_fields; passing a 3-tuple (name, value, content_type) instead of using add_field; passing a single scalar value or a string; passing a list longer than 2 elements.","commonSituations":"Building FormData from a dict.items() that includes non-file values mixed incorrectly; trying to use the (name, value, content_type) shorthand that some other libraries support; passing a list of lists where inner lists have more than 2 elements.","solutions":["Use add_field (singular) for fields with content_type or filename: form.add_field('name', value, content_type='text/plain')","Convert a dict to (name, value) tuples: form.add_fields(*my_dict.items())","For IOBase objects, ensure they are not wrapped in another container"],"exampleFix":"# before (3-tuple is rejected)\nform.add_fields(('file', data, 'application/pdf'))\n\n# after\nform.add_field('file', data, content_type='application/pdf')","handlingStrategy":"validation","validationCode":"from multidict import MultiDict, MultiDictProxy\nimport io\n\ndef validate_form_fields(fields):\n    for rec in fields:\n        if isinstance(rec, io.IOBase):\n            continue\n        if isinstance(rec, (MultiDict, MultiDictProxy)):\n            continue\n        if isinstance(rec, (list, tuple)) and len(rec) == 2:\n            continue\n        raise TypeError(f'Unsupported field type: {type(rec).__name__}. '\n                        f'Use add_field() for complex parameters.')","typeGuard":"def is_valid_form_field(rec) -> bool:\n    import io\n    from multidict import MultiDict, MultiDictProxy\n    return (\n        isinstance(rec, io.IOBase) or\n        isinstance(rec, (MultiDict, MultiDictProxy)) or\n        (isinstance(rec, (list, tuple)) and len(rec) == 2)\n    )","tryCatchPattern":null,"preventionTips":["Use add_field() (singular) when you need content_type or filename","Validate field collections before passing them to add_fields()","Keep (name, value) tuples exactly 2 elements long"],"tags":["form-data","type-error","multipart","validation"],"backgroundTag":null,"analyzedSha":"d041d4d0fd48c3f0832084d33be16cf1c4835f85","analyzedAt":"2026-08-11T20:44:15.550Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}