{"id":"e8215467631e4dde","repo":"aio-libs/aiohttp","slug":"passing-both-content-type-header-and-content-type","errorCode":null,"errorMessage":"passing both Content-Type header and content_type or charset params is forbidden","messagePattern":"passing both Content-Type header and content_type or charset params is forbidden","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"aiohttp/web_response.py","lineNumber":568,"sourceCode":"        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\n                body = text.encode(charset)\n                text = None\n        elif hdrs.CONTENT_TYPE in real_headers:\n            if content_type is not None or charset is not None:\n                raise ValueError(","sourceCodeStart":550,"sourceCodeEnd":586,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/c0ef574e29109210e96e652771ae4e7b88615fa4/aiohttp/web_response.py#L550-L586","documentation":"When you pass text=, the constructor populates Content-Type for you. But if you ALSO pass a Content-Type header AND a content_type/charset kwarg, the two sources conflict; this is detected at lines 566-572 and raises ValueError to avoid an ambiguous header.","triggerScenarios":"Calling Response(text='hi', headers={'Content-Type': 'text/plain'}, content_type='text/html') or any combination where headers contain Content-Type and content_type/charset kwargs are non-None while text is set.","commonSituations":"Building headers from a framework/helper that already injects Content-Type, then also passing content_type; merging a default-headers dict with explicit kwargs.","solutions":["Pick ONE source: either set Content-Type in headers, or use content_type+charset kwargs — not both.","Strip Content-Type from the headers dict before passing it when you intend to use content_type.","Let text= infer Content-Type and pass neither header nor kwargs."],"exampleFix":"# before\nresp = Response(text=body, headers={'Content-Type':'text/plain'}, content_type='text/html')\n\n# after\nresp = Response(text=body, content_type='text/html')","handlingStrategy":"validation","validationCode":"def build_response(text=None, headers=None, content_type=None, charset=None, **kw):\n    headers = dict(headers or {})\n    has_ct_header = any(k.lower() == 'content-type' for k in headers)\n    if has_ct_header and (content_type or charset):\n        # resolve the conflict: drop kwargs in favor of the header\n        content_type = charset = None\n    return Response(text=text, headers=headers, content_type=content_type, charset=charset, **kw)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Choose exactly one Content-Type source: headers dict OR content_type/charset kwargs.","Strip Content-Type from shared/default headers before adding content_type.","Let text= infer Content-Type when possible."],"tags":["http","headers","content-type","conflict","response"],"analyzedSha":"c0ef574e29109210e96e652771ae4e7b88615fa4","analyzedAt":"2026-08-04T19:51:05.467Z","schemaVersion":2}