{"id":"ffd4d050ec029d61","repo":"aio-libs/aiohttp","slug":"content-type-must-be-an-instance-of-str-got-s","errorCode":null,"errorMessage":"content_type must be an instance of str. Got: %s","messagePattern":"content_type must be an instance of str\\. Got: (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"aiohttp/formdata.py","lineNumber":74,"sourceCode":"    ) -> None:\n        if isinstance(value, (io.IOBase, bytes, bytearray, memoryview)):\n            self._is_multipart = True\n\n        _safe_header(name)\n        type_options: MultiDict[str] = MultiDict({\"name\": name})\n        if filename is not None and not isinstance(filename, str):\n            raise TypeError(\"filename must be an instance of str. Got: %s\" % filename)\n        if filename is None and isinstance(value, io.IOBase):\n            filename = guess_filename(value, name)\n        if filename is not None:\n            _safe_header(filename)\n            type_options[\"filename\"] = filename\n            self._is_multipart = True\n\n        headers = {}\n        if content_type is not None:\n            if not isinstance(content_type, str):\n                raise TypeError(\n                    \"content_type must be an instance of str. Got: %s\" % content_type\n                )\n            _safe_header(content_type)\n            headers[hdrs.CONTENT_TYPE] = content_type\n            self._is_multipart = True\n\n        self._fields.append((type_options, headers, value))\n\n    def add_fields(self, *fields: Any) -> None:\n        to_add: deque[Any] = deque(fields)\n\n        while to_add:\n            rec = to_add.popleft()\n\n            if isinstance(rec, io.IOBase):\n                k = guess_filename(rec, \"unknown\")\n                self.add_field(k, rec)  # type: ignore[arg-type]\n","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/c0ef574e29109210e96e652771ae4e7b88615fa4/aiohttp/formdata.py#L56-L92","documentation":"Raised by FormData.add_field when content_type is not None but not a str. Content-Type becomes a literal HTTP header value, so non-string types are rejected up front with a TypeError. Setting content_type also forces multipart mode (self._is_multipart = True) after the type check passes.","triggerScenarios":"form.add_field('img', data, content_type=None) is fine, but content_type=123 or a mimetypes.guess_type tuple element used directly fails. Passing a content-type with non-ASCII bytes object also fails.","commonSituations":"Using mimetypes.guess_type(file)[0] which can return None and then defaulting incorrectly; passing a tuple instead of the string; dynamically building content_type from a lookup dict that returns int codes.","solutions":["Ensure content_type is a plain str or None.","Guard: content_type=ct if isinstance(ct, str) else None.","Default to 'application/octet-stream' when mimetypes returns None."],"exampleFix":"// before\nct = mimetypes.guess_type(name)[0]\nform.add_field('f', data, content_type=ct)\n// after\nct = mimetypes.guess_type(name)[0] or 'application/octet-stream'\nform.add_field('f', data, content_type=ct)","handlingStrategy":"type-guard","validationCode":"def safe_content_type(ct):\n    if ct is None:\n        return None\n    if not isinstance(ct, str):\n        raise TypeError('content_type must be str')\n    return ct","typeGuard":"def is_str_or_none(ct) -> bool:\n    return ct is None or isinstance(ct, str)","tryCatchPattern":null,"preventionTips":["Default mimetypes.guess_type results to 'application/octet-stream'.","Never pass tuples or ints as content_type.","Document content_type as str | None at form-building helpers."],"tags":["formdata","type-error","validation","multipart","content-type"],"analyzedSha":"c0ef574e29109210e96e652771ae4e7b88615fa4","analyzedAt":"2026-08-04T19:51:05.467Z","schemaVersion":2}