aio-libs/aiohttp · error · TypeError
Only io.IOBase, multidict and (name, file) pairs allowed…
Error message
Only io.IOBase, multidict and (name, file) pairs allowed, use .add_field() for passing more complex parameters, got {rec!r} What it means
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.
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
Example fix
# before (3-tuple is rejected)
form.add_fields(('file', data, 'application/pdf'))
# after
form.add_field('file', data, content_type='application/pdf') Defensive patterns
Strategy: validation
Validate before calling
from multidict import MultiDict, MultiDictProxy
import io
def validate_form_fields(fields):
for rec in fields:
if isinstance(rec, io.IOBase):
continue
if isinstance(rec, (MultiDict, MultiDictProxy)):
continue
if isinstance(rec, (list, tuple)) and len(rec) == 2:
continue
raise TypeError(f'Unsupported field type: {type(rec).__name__}. '
f'Use add_field() for complex parameters.') Type guard
def is_valid_form_field(rec) -> bool:
import io
from multidict import MultiDict, MultiDictProxy
return (
isinstance(rec, io.IOBase) or
isinstance(rec, (MultiDict, MultiDictProxy)) or
(isinstance(rec, (list, tuple)) and len(rec) == 2)
) Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- content_type must be an instance of str. Got
- filename must be an instance of str. Got
- Can not serialize value type: %r headers: %r value: %r
- Multipart field missing name.
- boundary missed for Content-Type
AI-assisted analysis of aio-libs/aiohttp@d041d4d0fd (2026-08-11).
Data as JSON: /api/errors/1379bd6dd2294418.
Report an issue: GitHub.
Appendix: source
Thrown at aiohttp/formdata.py:101
def add_fields(self, *fields: Any) -> None:
to_add: deque[Any] = deque(fields)
while to_add:
rec = to_add.popleft()
if isinstance(rec, io.IOBase):
k = guess_filename(rec, "unknown")
self.add_field(k, rec) # type: ignore[arg-type]
elif isinstance(rec, (MultiDictProxy, MultiDict)):
to_add.extend(rec.items())
elif isinstance(rec, (list, tuple)) and len(rec) == 2:
k, fp = rec
self.add_field(k, fp)
else:
raise TypeError(
"Only io.IOBase, multidict and (name, file) "
"pairs allowed, use .add_field() for passing "
f"more complex parameters, got {rec!r}"
)
def _gen_form_urlencoded(self) -> payload.BytesPayload:
# form data (x-www-form-urlencoded)
data = []
for type_options, _, value in self._fields:
if not isinstance(value, str):
raise TypeError(f"expected str, got {value!r}")
data.append((type_options["name"], value))
charset = self._charset if self._charset is not None else "utf-8"
if charset == "utf-8":
content_type = "application/x-www-form-urlencoded"
else:View on GitHub (pinned to d041d4d0fd)