{"id":"4fc31d6ad99080ec","repo":"psf/requests","slug":"streamed-bodies-and-files-are-mutually-exclusive","errorCode":null,"errorMessage":"Streamed bodies and files are mutually exclusive.","messagePattern":"Streamed bodies and files are mutually exclusive\\.","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"src/requests/models.py","lineNumber":623,"sourceCode":"                length = super_len(data)\n            except (TypeError, AttributeError, UnsupportedOperation):\n                length = None\n\n            body = data\n\n            if getattr(body, \"tell\", None) is not None:\n                # Record the current file position before reading.\n                # This will allow us to rewind a file in the event\n                # of a redirect.\n                try:\n                    self._body_position = body.tell()  # type: ignore[union-attr]  # guarded by getattr check\n                except OSError:\n                    # This differentiates from None, allowing us to catch\n                    # a failed `tell()` later when trying to rewind the body\n                    self._body_position = object()\n\n            if files:\n                raise NotImplementedError(\n                    \"Streamed bodies and files are mutually exclusive.\"\n                )\n\n            if length:\n                self.headers[\"Content-Length\"] = builtin_str(length)\n            else:\n                self.headers[\"Transfer-Encoding\"] = \"chunked\"\n        else:\n            # After is_stream filtering, remaining data is raw (not streamed)\n            raw_data = cast(\"_t.RawDataType | None\", data)\n\n            # Multi-part file uploads.\n            if files:\n                (body, content_type) = self._encode_files(files, raw_data)\n            else:\n                if raw_data:\n                    body = self._encode_params(raw_data)\n                    if isinstance(data, basestring) or _t.has_read(data):","sourceCodeStart":605,"sourceCodeEnd":641,"githubUrl":"https://github.com/psf/requests/blob/414f0513c33883adf6f2b46901d4f0b38a455851/src/requests/models.py#L605-L641","documentation":"A `NotImplementedError` raised in `PreparedRequest.prepare_body` when `data` is a stream (a generator, iterator, or file-like object that isn't a str/bytes/list/tuple/dict) and `files` is also supplied. A streamed body is sent as-is (chunked or with Content-Length), while `files` requires building a multipart body in memory — the two body sources cannot be combined, and requests has no implementation to interleave them.","triggerScenarios":"`requests.post(url, data=open('big.bin','rb'), files={'f': fh})`, or `data=my_generator()` together with `files=`. Any call where `prepare_body` classifies `data` as iterable-but-not-basic (src/requests/models.py:602-603) while `files` is truthy.","commonSituations":"Upgrading an upload endpoint from streaming raw bytes to multipart and leaving the old file-object `data=` in place; passing a file handle to `data=` when the intent was `files=`; wrapper functions that forward both parameters unconditionally.","solutions":["Pick one body style: for multipart uploads put the stream into `files` (`files={'file': open('big.bin','rb')}`) and drop `data=` or make it a field dict.","For raw streaming uploads, use `data=fileobj` alone and set the Content-Type header yourself; do not pass `files`.","For streaming multipart of large files, use `requests_toolbelt.MultipartEncoder` and pass it as `data=` with its content type header."],"exampleFix":"# before\nrequests.post(url, data=open('big.bin', 'rb'), files={'meta': ('m.json', meta)})\n\n# after\nrequests.post(url, files={'file': open('big.bin', 'rb'),\n                          'meta': ('m.json', meta, 'application/json')})","handlingStrategy":"validation","validationCode":"is_stream = data is not None and not isinstance(data, (str, bytes, dict, list, tuple))\nif is_stream and files:\n    raise ValueError(\"pick one: a streamed body (file-like/generator data=) OR multipart files=\")","typeGuard":"def is_streamed_body(data):\n    return data is not None and not isinstance(data, (str, bytes, dict, list, tuple)) and (hasattr(data, \"read\") or hasattr(data, \"__iter__\"))","tryCatchPattern":"try:\n    resp = requests.post(url, data=body_stream, files=files)\nexcept NotImplementedError:\n    # can't mix a generator/file-like data= with files=; use multipart for everything\n    resp = requests.post(url, files={**files, \"body\": body_stream})","preventionTips":["Choose one upload mode per request: streamed raw body (data=file/generator) or multipart (files=)","To stream a file inside a multipart upload, pass the open file object inside files=, not data=","Note this raises NotImplementedError, not ValueError — catch accordingly"],"tags":["python","requests","streaming","multipart","request-body"],"analyzedSha":"414f0513c33883adf6f2b46901d4f0b38a455851","analyzedAt":"2026-07-31T19:24:57.696Z","schemaVersion":2}