{"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":"validation","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/c0ef574e29109210e96e652771ae4e7b88615fa4/aiohttp/formdata.py#L83-L119","documentation":"Raised by FormData.add_fields when an element of the *fields sequence is not an io.IOBase, not a MultiDict/MultiDictProxy, and not a 2-element list/tuple. add_fields dispatches on the runtime type of each record; anything else falls into the else branch and raises TypeError, pointing the user at add_field() for complex parameters.","triggerScenarios":"Passing FormData({'k': v}) is fine (dict converted), but FormData('plain string'), FormData(42), FormData((1,2,3)) (3-tuple), or FormData([{'nested': 'dict'}]) triggers it. Also FormData(SomeObj()).","commonSituations":"Passing a single string value directly to FormData instead of a list of pairs; passing 3-tuples (name, value, content_type) which add_fields does not unpack; passing a single non-file object.","solutions":["Use add_field() for each field with explicit name/value.","Pass a list of (name, value) 2-tuples.","Pass a MultiDict of name/value pairs for simple forms."],"exampleFix":"// before\nform = FormData([('field', val, 'text/plain')])  # 3-tuple not unpacked\n// after\nform = FormData()\nform.add_field('field', val, content_type='text/plain')","handlingStrategy":"validation","validationCode":"def normalize_fields(fields):\n    if isinstance(fields, dict):\n        return [(k, v) for k, v in fields.items()]\n    if isinstance(fields, (list, tuple)):\n        for rec in fields:\n            assert isinstance(rec, (list, tuple)) and len(rec) == 2, f'bad record {rec!r}'\n        return list(fields)\n    raise TypeError('fields must be dict or list of 2-tuples')","typeGuard":"def is_valid_field_record(rec) -> bool:\n    import io\n    from multidict import MultiDict, MultiDictProxy\n    return (\n        isinstance(rec, io.IOBase)\n        or isinstance(rec, (MultiDict, MultiDictProxy))\n        or (isinstance(rec, (list, tuple)) and len(rec) == 2)\n    )","tryCatchPattern":null,"preventionTips":["Prefer add_field() for anything beyond simple (name, value) pairs.","Never pass 3-tuples; use add_field(name, value, content_type=...).","Normalize input to a list of 2-tuples before constructing FormData."],"tags":["formdata","type-error","multipart","api-misuse"],"analyzedSha":"c0ef574e29109210e96e652771ae4e7b88615fa4","analyzedAt":"2026-08-04T19:51:05.467Z","schemaVersion":2}