aio-libs/aiohttp · error · ValueError
only one of data, text, or body should be specified
Error message
only one of data, text, or body should be specified
What it means
Raised by `aiohttp.web.json_response` when the caller passes both `data=` (the value to be JSON-encoded) and `text=` or `body=`. json_response encodes `data` into a JSON string and assigns it to text; passing text/body too creates an ambiguous source, so it is rejected.
Solutions
- Pass exactly one: `data=` for objects to encode, `text=` for an already-encoded JSON string, `body=` for already-encoded bytes.
- Use `json_response(data=obj)` in the normal case and let json_response serialize.
- For orjson (bytes output) use `aiohttp.web.json_response(data=obj, dumps=lambda d: orjson.dumps(d))` won't work — use the dedicated bytes variant `json_response_with_bytes` or build Response(body=...) directly.
- Audit helper signatures to ensure mutually-exclusive kwargs.
Example fix
// before return json_response(data=payload, text=json.dumps(payload)) // after return json_response(data=payload) # json_response does the encoding
Defensive patterns
Strategy: validation
Validate before calling
def safe_json_response(data=sentinel, text=None, body=None, **kw):
if data is not sentinel:
assert not (text or body), 'pass only one of data, text, or body'
return json_response(data=data, text=text, body=body, **kw) Prevention
- Pass exactly one of data=, text=, or body= to json_response.
- Let json_response serialize the object — do not pre-encode.
- For pre-encoded bytes, use the bytes-encoder variant with body= only.
- Audit wrapper signatures for mutually-exclusive kwargs.
When it happens
Trigger: Calling `json_response(data=obj, text='literal')` or `json_response(data=obj, body=b'raw')`. Also triggered by helper wrappers that forward *args/**kwargs and accidentally pass both.
Common situations: Conditional handlers that sometimes pre-serialize and sometimes pass the raw object; refactoring that left both arguments wired; copy-pasting a Response() call into json_response() without dropping text/body.
Related errors
- only one of data or body should be specified
- body and text are not allowed together
- Cannot call write() after write_eof()
- Cannot call write() before prepare()
- charset must not be in content_type argument
AI-assisted analysis of aio-libs/aiohttp@d041d4d0fd (2026-08-11).
Data as JSON: /api/errors/f9d77632386f4a95.
Report an issue: GitHub.
Appendix: source
Thrown at aiohttp/web_response.py:752
)
self._headers[hdrs.CONTENT_ENCODING] = coding.value
self._headers[hdrs.CONTENT_LENGTH] = str(len(self._compressed_body))
def json_response(
data: Any = sentinel,
*,
text: str | None = None,
body: bytes | None = None,
status: int = 200,
reason: str | None = None,
headers: LooseHeaders | None = None,
content_type: str = "application/json",
dumps: JSONEncoder = json.dumps,
) -> Response:
if data is not sentinel:
if text or body:
raise ValueError("only one of data, text, or body should be specified")
else:
text = dumps(data)
return Response(
text=text,
body=body,
status=status,
reason=reason,
headers=headers,
content_type=content_type,
)
def json_bytes_response(
data: Any = sentinel,
*,
dumps: JSONBytesEncoder,
body: bytes | None = None,
status: int = 200,View on GitHub (pinned to d041d4d0fd)