aio-libs/aiohttp · error · ValueError

body and text are not allowed together

Error message

body and text are not allowed together

What it means

Raised by the Response constructor when both `body` and `text` kwargs are passed. The two are alternative ways to supply the response payload: `text` is encoded to bytes using the charset, while `body` is raw bytes. Passing both is ambiguous (which one wins?) so aiohttp rejects it.

Solutions

  1. Pass exactly one of `body=` or `text=`. Use `text=` for str payloads (it sets content_type/charset), `body=` for pre-encoded bytes.
  2. In helper functions, normalize to one channel: `if text is not None: body = text.encode(charset); text = None`.
  3. Use `json_response(data=...)` for JSON, which encodes for you and accepts only one source.
  4. Add an assertion in your wrappers: `assert (body is None) or (text is None)`.

Example fix

// before
return Response(body=content.encode(), text=content)

// after
return Response(text=content)  # let aiohttp encode with charset
Defensive patterns

Strategy: validation

Validate before calling

def make_response(*, body=None, text=None, **kw):
    assert body is None or text is None, 'pass only one of body or text'
    return Response(body=body, text=text, **kw)

Prevention

When it happens

Trigger: Constructing `Response(body=b'data', text='data')`, or a helper that conditionally sets both and forwards them. Also `Response(text=text, body=payload)` when both branches of a conditional populate their variable.

Common situations: Refactoring that left both arguments wired in; helper functions with `body=None, text=None` defaults where the caller passes both; building an error response that mistakenly forwards both the rendered HTML and a pre-encoded bytes copy.

Related errors


AI-assisted analysis of aio-libs/aiohttp@d041d4d0fd (2026-08-11). Data as JSON: /api/errors/de6365bac25d2740. Report an issue: GitHub.

Appendix: source

Thrown at aiohttp/web_response.py:555

    _compressed_body: bytes | None = None
    _send_headers_immediately = False

    def __init__(
        self,
        *,
        body: Any = None,
        status: int = 200,
        reason: str | None = None,
        text: str | None = None,
        headers: LooseHeaders | None = None,
        content_type: str | None = None,
        charset: str | None = None,
        zlib_executor_size: int = MAX_SYNC_CHUNK_SIZE,
        zlib_executor: Executor | None = None,
    ) -> None:
        if body is not None and text is not None:
            raise ValueError("body and text are not allowed together")

        if headers is None:
            real_headers: CIMultiDict[str] = CIMultiDict()
        else:
            real_headers = CIMultiDict(headers)

        if content_type is not None and "charset" in content_type:
            raise ValueError("charset must not be in content_type argument")

        if text is not None:
            if hdrs.CONTENT_TYPE in real_headers:
                if content_type or charset:
                    raise ValueError(
                        "passing both Content-Type header and "
                        "content_type or charset params "
                        "is forbidden"
                    )
            else:

View on GitHub (pinned to d041d4d0fd)