{"record":{"id":"894b01cdfc73043c","repo":"aio-libs/aiohttp","slug":"charset-must-not-be-in-content-type-argument","errorCode":null,"errorMessage":"charset must not be in content_type argument","messagePattern":"charset must not be in content_type argument","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"aiohttp/web_response.py","lineNumber":563,"sourceCode":"        status: int = 200,\n        reason: str | None = None,\n        text: str | None = None,\n        headers: LooseHeaders | None = None,\n        content_type: str | None = None,\n        charset: str | None = None,\n        zlib_executor_size: int = MAX_SYNC_CHUNK_SIZE,\n        zlib_executor: Executor | None = None,\n    ) -> None:\n        if body is not None and text is not None:\n            raise ValueError(\"body and text are not allowed together\")\n\n        if headers is None:\n            real_headers: CIMultiDict[str] = CIMultiDict()\n        else:\n            real_headers = CIMultiDict(headers)\n\n        if content_type is not None and \"charset\" in content_type:\n            raise ValueError(\"charset must not be in content_type argument\")\n\n        if text is not None:\n            if hdrs.CONTENT_TYPE in real_headers:\n                if content_type or charset:\n                    raise ValueError(\n                        \"passing both Content-Type header and \"\n                        \"content_type or charset params \"\n                        \"is forbidden\"\n                    )\n            else:\n                # fast path for filling headers\n                if not isinstance(text, str):\n                    raise TypeError(\"text argument must be str (%r)\" % type(text))\n                if content_type is None:\n                    content_type = \"text/plain\"\n                if charset is None:\n                    charset = \"utf-8\"\n                real_headers[hdrs.CONTENT_TYPE] = content_type + \"; charset=\" + charset","sourceCodeStart":545,"sourceCodeEnd":581,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/web_response.py#L545-L581","documentation":"Raised by the Response constructor when the `content_type` kwarg string itself contains the substring 'charset' (e.g. 'text/html; charset=utf-8'). aiohttp manages charset separately via the `charset` kwarg and the `; charset=...` suffix is appended internally; embedding it in content_type would produce a malformed or duplicated header.","triggerScenarios":"Passing `Response(content_type='application/json; charset=utf-8')`, or copying a full Content-Type string from a config file/header straight into the `content_type=` argument.","commonSituations":"Copy-pasting Content-Type header values (which legitimately contain charset) into the content_type parameter that expects only the MIME type. Configuration files that store the full header. Naive porting of Flask/Django patterns where the full header string is accepted.","solutions":["Split the MIME type and charset: `Response(content_type='text/html', charset='utf-8')`.","Use `text=` which auto-derives `text/plain; charset=utf-8` (override content_type separately if needed).","If the string is user-supplied, parse out charset: split on ';', strip the charset param, pass the rest.","Sanitize config values by storing MIME type and charset as separate fields."],"exampleFix":"// before\nreturn Response(text=html, content_type='text/html; charset=utf-8')\n\n// after\nreturn Response(text=html, content_type='text/html', charset='utf-8')","handlingStrategy":"validation","validationCode":"def split_content_type(raw: str):\n    if ';' in raw:\n        ctype, _, params = raw.partition(';')\n        charset = None\n        for p in params.split(';'):\n            p = p.strip()\n            if p.lower().startswith('charset='):\n                charset = p.split('=', 1)[1]\n        return ctype.strip(), charset\n    return raw, None\n\nctype, cs = split_content_type(raw)\nreturn Response(text=t, content_type=ctype, charset=cs)","typeGuard":"def content_type_has_no_charset(ctype: str) -> bool:\n    return 'charset' not in ctype.lower()","tryCatchPattern":null,"preventionTips":["Pass MIME type only to content_type=; pass charset separately via charset=.","Parse user/config Content-Type strings before forwarding.","Store content_type and charset as separate config fields.","Beware copy-pasted Content-Type header values from other frameworks."],"tags":["aiohttp","web-response","constructor","content-type","charset"],"backgroundTag":null,"analyzedSha":"d041d4d0fd48c3f0832084d33be16cf1c4835f85","analyzedAt":"2026-08-11T20:44:15.550Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}