aio-libs/aiohttp · error · ValueError
Unsupported body type %r
Error message
Unsupported body type %r
What it means
The body setter tries to coerce non-bytes values via payload.PAYLOAD_REGISTRY.get (line 618). If no registered Payload type matches the object, it raises ValueError listing the unsupported type. Only bytes/bytearray pass directly; everything else needs a registered payload type (e.g. str, dict via aiohttp payload types).
Source
Thrown at aiohttp/web_response.py:620
self._zlib_executor_size = zlib_executor_size
self._zlib_executor = zlib_executor
@property
def body(self) -> bytes | bytearray | Payload | None:
return self._body
@body.setter
def body(self, body: Any) -> None:
if body is None:
self._body = None
elif isinstance(body, (bytes, bytearray)):
self._body = body
else:
try:
self._body = body = payload.PAYLOAD_REGISTRY.get(body)
except payload.LookupError:
raise ValueError("Unsupported body type %r" % type(body))
headers = self._headers
# set content-type
if hdrs.CONTENT_TYPE not in headers:
headers[hdrs.CONTENT_TYPE] = body.content_type
# copy payload headers
if body.headers:
for key, value in body.headers.items():
if key not in headers:
headers[key] = value
self._compressed_body = None
@property
def text(self) -> str | None:
if self._body is None:View on GitHub (pinned to c0ef574e29)
Solutions
- Encode to bytes first: resp.body = str(obj).encode() or json.dumps(obj).encode().
- For str use text=, for JSON use json_response(data=...).
- Register a custom Payload type via payload.PAYLOAD_REGISTRY.register if you need first-class support.
Example fix
# before
resp = Response()
resp.body = {'key': 'value'} # dict has no payload by default -> ValueError
# after
from aiohttp import json_response
resp = json_response({'key': 'value'}) Defensive patterns
Strategy: type-guard
Validate before calling
def coerce_body(value):
if isinstance(value, (bytes, bytearray)):
return value
if isinstance(value, str):
return value.encode()
raise TypeError(f'Use json_response/text= for {type(value)}; body= needs bytes') Type guard
def is_bytes_body(value) -> bool:
return isinstance(value, (bytes, bytearray)) Prevention
- Encode str/dict/list to bytes before assigning to body.
- Use Response(text=...) for str and json_response(data=...) for objects.
- Register a custom Payload type only if you need reusable first-class support.
When it happens
Trigger: Assigning resp.body = some_custom_object that has no registered Payload; passing an int, list, or arbitrary class instance; resp.body = a generator (not a registered payload stream type).
Common situations: Setting body to an object that isn't bytes and has no registered aiohttp payload serializer; forgetting that Response(text=...) handles str while body= does not.
Related errors
- Unsupported type for last_modified: {type(value).__name__}
- Unsupported etag type: {type(value)}. etag must be str, ETag
- text argument must be str (%r)
- Got more than {limit} bytes when reading: {line!r}.
- Not enough data to satisfy content length header (received {
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/177be9342c2a4411.json.
Report an issue: GitHub.