{"record":{"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":"exception","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/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/web_response.py#L550-L586","documentation":"Raised by the Response constructor in the `text is not None` branch when the caller supplies both a Content-Type header (in `headers=`) AND a `content_type=` or `charset=` kwarg. The two channels for setting Content-Type conflict; aiohttp refuses to silently pick one and produce an inconsistent header.","triggerScenarios":"Calling `Response(text='hi', headers={'Content-Type': 'text/html'}, content_type='text/plain')`, or passing charset alongside a headers dict that already carries Content-Type. Common when wrapping responses with default headers and then overriding per-call.","commonSituations":"Middleware that injects a default Content-Type header into all responses; then a handler also passes content_type. Helpers that merge a base headers dict with caller-supplied content_type. Copy-pasting a headers dict that contains Content-Type and then adding the kwarg 'just in case'.","solutions":["Choose ONE channel: either set Content-Type via `headers=` OR via `content_type=`/`charset=` kwargs, never both.","If middleware sets defaults, have it omit Content-Type when the handler will pass content_type.","Strip Content-Type from the headers dict before constructing the Response if you intend to use the kwargs.","Build the headers dict without Content-Type and let the kwargs drive it."],"exampleFix":"// before\nreturn Response(\n    text=body,\n    headers={'Content-Type': 'text/html'},\n    content_type='text/html',\n)\n\n// after\nreturn Response(text=body, content_type='text/html')","handlingStrategy":"validation","validationCode":"def build_response(text=None, body=None, headers=None, content_type=None, charset=None):\n    h = CIMultiDict(headers or {})\n    if 'Content-Type' in h:\n        assert content_type is None and charset is None, \\\n            'do not pass content_type/charset with a Content-Type header'\n    return Response(text=text, body=body, headers=h, content_type=content_type, charset=charset)","typeGuard":"from multidict import CIMultiDict\n\ndef headers_have_content_type(headers) -> bool:\n    return any(k.lower() == 'content-type' for k in (headers or {}).keys())","tryCatchPattern":null,"preventionTips":["Choose one channel for Content-Type: headers= OR content_type=/charset=.","Strip Content-Type from base headers when handlers will set content_type.","Middleware should not inject Content-Type if handlers set it.","Document the convention in helper signatures."],"tags":["aiohttp","web-response","constructor","content-type","headers"],"backgroundTag":null,"analyzedSha":"d041d4d0fd48c3f0832084d33be16cf1c4835f85","analyzedAt":"2026-08-11T20:44:15.550Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}