{"record":{"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/8068356288978c4f54661ae6f95afe0e0831885e/src/requests/models.py#L605-L641","documentation":"Raised by PreparedRequest.prepare_body when both a streamed (iterable, non-str/bytes/list/tuple/Mapping) body and a files= argument are supplied. The multipart encoder needs to size and frame the body, which is incompatible with an open-ended stream. requests refuses the combination rather than guessing how to interleave them.","triggerScenarios":"Calling requests.post(url, data=generator_obj, files={'f': f}) where data is a generator/iterator; passing a streaming source (e.g. a file-like object yielding chunks) together with files for multipart upload; mixing chunked upload semantics with multipart.","commonSituations":"Upload code that evolved from form-fields+files to streaming content but kept the files= argument; pipelines that wrap data= in a generator for memory efficiency and forgot to remove files=.","solutions":["If you need streaming, drop files= and send the stream as the raw body (data=stream) with an explicit Content-Type.","If you need multipart, materialize the data into a dict/list (not a generator) and keep files=.","Choose one upload strategy per request — never both."],"exampleFix":"// before\ndef gen(): yield b'chunk'\nrequests.post(url, data=gen(), files={'f': open('x','rb')})\n\n// after\n# option A: streaming, no multipart\nrequests.post(url, data=gen(), headers={'Content-Type': 'application/octet-stream'})\n# option B: multipart, materialize fields\nrequests.post(url, data={'k': 'v'}, files={'f': open('x','rb')})","handlingStrategy":"validation","validationCode":"from collections.abc import Iterable, Mapping\n\ndef is_streaming_body(data) -> bool:\n    if data is None or isinstance(data, (str, bytes, list, tuple, Mapping)):\n        return False\n    return isinstance(data, Iterable) or hasattr(data, '__iter__')\n\ndef assert_not_streaming_with_files(data, files):\n    if files and is_streaming_body(data):\n        raise ValueError('cannot combine streaming data= with files=')","typeGuard":"from collections.abc import Iterable, Mapping\n\ndef is_materialized(data) -> bool:\n    return data is None or isinstance(data, (str, bytes, list, tuple, Mapping))","tryCatchPattern":"# NotImplementedError signals a misuse; fix the caller rather than catch.\n# Defensive form:\nfrom collections.abc import Iterable, Mapping\n\nif files and not (data is None or isinstance(data, (str, bytes, list, tuple, Mapping))):\n    # materialize or drop files\n    data = list(data) if isinstance(data, Iterable) else data\nrequests.post(url, data=data, files=files)","preventionTips":["Never combine a generator/iterator data= with files=.","Choose one upload strategy per request (streaming raw body OR multipart).","Materialize generators into lists before multipart uploads."],"tags":["upload","streaming","multipart","notimplemented","http"],"backgroundTag":null,"analyzedSha":"8068356288978c4f54661ae6f95afe0e0831885e","analyzedAt":"2026-08-11T20:11:09.238Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}