aio-libs/aiohttp · error · RuntimeError

Setting charset for application/octet-stream doesn't make se

Error message

Setting charset for application/octet-stream doesn't make sense, setup content_type first

What it means

StreamResponse (and Response) default their content_type to application/octet-stream. The charset setter refuses to attach a charset to this binary type, because a charset parameter is meaningless for opaque binary data and would mislead clients. You must set a meaningful text content_type (e.g. text/plain, application/json) before assigning charset.

Source

Thrown at aiohttp/web_response.py:240

        # Just a placeholder for adding setter
        return super().content_type

    @content_type.setter
    def content_type(self, value: str) -> None:
        self.content_type  # read header values if needed
        self._content_type = str(value)
        self._generate_content_type_header()

    @property
    def charset(self) -> str | None:
        # Just a placeholder for adding setter
        return super().charset

    @charset.setter
    def charset(self, value: str | None) -> None:
        ctype = self.content_type  # read header values if needed
        if ctype == "application/octet-stream":
            raise RuntimeError(
                "Setting charset for application/octet-stream "
                "doesn't make sense, setup content_type first"
            )
        assert self._content_dict is not None
        if value is None:
            self._content_dict.pop("charset", None)
        else:
            self._content_dict["charset"] = str(value).lower()
        self._generate_content_type_header()

    @property
    def last_modified(self) -> datetime.datetime | None:
        """The value of Last-Modified HTTP header, or None.

        This header is represented as a `datetime` object.
        """
        return parse_http_date(self._headers.get(hdrs.LAST_MODIFIED))

View on GitHub (pinned to c0ef574e29)

Solutions

  1. Set a text content_type before charset: resp = StreamResponse(content_type='text/plain') then resp.charset = 'utf-8'.
  2. If you have static text/JSON, use Response(text=...) which auto-sets content_type and charset for you.
  3. If you must override on an existing response, assign resp.content_type = 'application/json' first, then resp.charset.

Example fix

# before
resp = StreamResponse()
resp.charset = 'utf-8'  # raises RuntimeError

# after
resp = StreamResponse(content_type='text/plain')
resp.charset = 'utf-8'
Defensive patterns

Strategy: validation

Validate before calling

def safe_set_charset(resp, charset):
    if resp.content_type == 'application/octet-stream':
        resp.content_type = 'text/plain'  # or your intended text type
    resp.charset = charset

Type guard

def is_text_content_type(ct: str) -> bool:
    return not ct.startswith('application/octet-stream') and (
        ct.startswith('text/') or 'json' in ct or 'xml' in ct or 'charset' in ct
    )

Prevention

When it happens

Trigger: Calling `resp.charset = 'utf-8'` on a freshly constructed StreamResponse without first setting content_type, or passing content_type='application/octet-stream' and then assigning charset. The check at line 239 compares ctype == 'application/octet-stream' exactly.

Common situations: Devs copy a Response(text=...) example into a manual StreamResponse and try to set charset directly; serving dynamically generated JSON/text as a stream; calling `resp.charset = 'utf-8'` after `StreamResponse()` with no content_type argument.

Related errors


AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04). Data as JSON: /data/errors/f9e9ce57e36556ba.json. Report an issue: GitHub.