aio-libs/aiohttp · error · TypeError
expected str, got
Error message
expected str, got {value!r} What it means
FormData._gen_form_urlencoded raises TypeError when generating application/x-www-form-urlencoded body data and a field value is not a str. The urlencoded format only supports string values; binary or file content triggers this error. This fires when is_multipart is False (no files were added) but a non-str value slipped in.
Solutions
- Convert non-str values to str before adding: form.add_field('count', str(42))
- If you have file/binary data, ensure at least one field sets is_multipart (use add_field with a file or content_type to switch to multipart encoding)
- Pre-process your data dict to stringify all values
Example fix
# before
form.add_field('quantity', 42)
form.add_field('price', 19.99)
# after
form.add_field('quantity', str(42))
form.add_field('price', str(19.99)) Defensive patterns
Strategy: validation
Validate before calling
def stringify_form_values(fields):
"""Convert all values to str for urlencoded form data."""
return [(name, str(value) if not isinstance(value, str) else value)
for name, value in fields] Prevention
- Always str() non-string values before adding them to FormData
- Use multipart encoding (add a file field) if you have binary data
- Type-check form values in a preprocessing step
When it happens
Trigger: Adding an int, float, bool, bytes, or object value to FormData that will be serialized as urlencoded (no multipart fields present). The error surfaces at serialization time, not at add_field time, because the multipart flag is only set by file/content_type fields.
Common situations: Form data with mixed numeric values from a calculation: form.add_field('count', 42); passing a bool value: form.add_field('active', True); passing bytes that were not intended as file content.
Related errors
- Can not serialize value type: %r headers: %r value: %r
- content_type must be an instance of str. Got
- filename must be an instance of str. Got
- Only io.IOBase, multidict and (name, file) pairs allowed…
- value argument must be byte-ish, not
AI-assisted analysis of aio-libs/aiohttp@d041d4d0fd (2026-08-11).
Data as JSON: /api/errors/f78b10ef8a0e6cf7.
Report an issue: GitHub.
Appendix: source
Thrown at aiohttp/formdata.py:112
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:
content_type = "application/x-www-form-urlencoded; charset=%s" % charset
return payload.BytesPayload(
urlencode(data, doseq=True, encoding=charset).encode(),
content_type=content_type,
)
def _gen_form_data(self) -> multipart.MultipartWriter:
"""Encode a list of fields using the multipart/form-data MIME format"""
for dispparams, headers, value in self._fields:
try:View on GitHub (pinned to d041d4d0fd)