aio-libs/aiohttp · error · TypeError
filename must be an instance of str. Got
Error message
filename must be an instance of str. Got: %s
What it means
FormData.add_field raises TypeError when the filename keyword argument is not None and not a str instance. The filename is used in the Content-Disposition header of the multipart part, so it must be a plain string. This is a type validation guard, not a runtime I/O error.
Solutions
- Convert the filename to str: form.add_field('file', data, filename=str(my_path))
- If using pathlib.Path, call .name then str(): filename=str(path.name)
- Ensure the filename comes from a string source, not bytes or Path
Example fix
# before
from pathlib import Path
form.add_field('upload', f, filename=Path('/tmp/photo.jpg'))
# after
form.add_field('upload', f, filename=str(Path('/tmp/photo.jpg').name)) Defensive patterns
Strategy: type-guard
Validate before calling
def coerce_filename(fn):
if fn is None:
return None
if isinstance(fn, bytes):
return fn.decode('utf-8')
if not isinstance(fn, str):
return str(fn)
return fn
form.add_field('file', data, filename=coerce_filename(my_filename)) Type guard
def is_valid_filename(fn) -> bool:
return fn is None or isinstance(fn, str) Try / catch
try:
form.add_field('file', data, filename=fn)
except TypeError as e:
if 'filename must be an instance of str' in str(e):
form.add_field('file', data, filename=str(fn))
raise Prevention
- Always wrap pathlib.Path filenames with str() before passing to add_field
- Use static type checking (mypy) to catch non-str filename arguments at lint time
When it happens
Trigger: Calling form.add_field('file', data, filename=Path('photo.jpg')) or passing an int, bytes, or other non-str value as the filename argument. Common when using pathlib.Path objects or os.path.join results without converting to str.
Common situations: Passing a pathlib.Path object directly as filename; using os.path.basename which may return bytes on some systems; passing an integer or float from a computed filename.
Related errors
- content_type must be an instance of str. Got
- Only io.IOBase, multidict and (name, file) pairs allowed…
- 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/1c2dd7d5de19f6ed.
Report an issue: GitHub.
Appendix: source
Thrown at aiohttp/formdata.py:63
@property
def is_multipart(self) -> bool:
return self._is_multipart
def add_field(
self,
name: str,
value: Any,
*,
content_type: str | None = None,
filename: str | None = None,
) -> None:
if isinstance(value, (io.IOBase, bytes, bytearray, memoryview)):
self._is_multipart = True
_safe_header(name)
type_options: MultiDict[str] = MultiDict({"name": name})
if filename is not None and not isinstance(filename, str):
raise TypeError("filename must be an instance of str. Got: %s" % filename)
if filename is None and isinstance(value, io.IOBase):
filename = guess_filename(value, name)
if filename is not None:
_safe_header(filename)
type_options["filename"] = filename
self._is_multipart = True
headers = {}
if content_type is not None:
if not isinstance(content_type, str):
raise TypeError(
"content_type must be an instance of str. Got: %s" % content_type
)
_safe_header(content_type)
headers[hdrs.CONTENT_TYPE] = content_type
self._is_multipart = True
self._fields.append((type_options, headers, value))View on GitHub (pinned to d041d4d0fd)