{"id":"1dbcf8ed1b12d2cf","repo":"psf/requests","slug":"files-must-be-provided","errorCode":null,"errorMessage":"Files must be provided.","messagePattern":"Files must be provided\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/requests/models.py","lineNumber":195,"sourceCode":"                        )\n            return urlencode(result, doseq=True)\n        else:\n            return data  # type: ignore[return-value]  # unreachable for valid _t.DataType\n\n    @staticmethod\n    def _encode_files(\n        files: _t.FilesType, data: _t.RawDataType | None\n    ) -> tuple[bytes, str]:\n        \"\"\"Build the body for a multipart/form-data request.\n\n        Will successfully encode files when passed as a dict or a list of\n        tuples. Order is retained if data is a list of tuples but arbitrary\n        if parameters are supplied as a dict.\n        The tuples may be 2-tuples (filename, fileobj), 3-tuples (filename, fileobj, contentype)\n        or 4-tuples (filename, fileobj, contentype, custom_headers).\n        \"\"\"\n        if not files:\n            raise ValueError(\"Files must be provided.\")\n        elif isinstance(data, basestring):\n            raise ValueError(\"Data must not be a string.\")\n\n        new_fields: list[RequestField | tuple[str, bytes]] = []\n        fields = to_key_val_list(data or {})\n        files = to_key_val_list(files or {})\n\n        for field, val in fields:\n            if isinstance(val, basestring) or not hasattr(val, \"__iter__\"):\n                val = [val]\n            for v in val:\n                if v is not None:\n                    # Don't call str() on bytestrings: in Py3 it all goes wrong.\n                    if not isinstance(v, bytes):\n                        v = str(v)\n\n                    new_fields.append(\n                        (","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/psf/requests/blob/414f0513c33883adf6f2b46901d4f0b38a455851/src/requests/models.py#L177-L213","documentation":"Raised by `PreparedRequest._encode_files` in requests when it is asked to build a multipart/form-data body but the `files` argument is empty or falsy. The method exists solely to encode files (optionally merged with form data), so an empty `files` dict/list means the caller reached the multipart path by mistake. It is a guard against silently producing an empty multipart body.","triggerScenarios":"Calling `requests.post(url, files={})` or `files=[]` (empty but the multipart path is still invoked internally in some flows), or calling `PreparedRequest._encode_files(files, data)` / `prepare_body` directly with a falsy `files` value while expecting multipart encoding. Also hit by test harnesses or wrappers that invoke `_encode_files` themselves.","commonSituations":"A file-upload helper builds the `files` dict dynamically (e.g. from a directory listing or user selection) and ends up empty; code passes `files=None`-vs-`files={}` inconsistently; frameworks that wrap requests and always route through the multipart encoder even when no files were attached.","solutions":["Ensure the files mapping is non-empty before making the request: `if files: requests.post(url, files=files) else: requests.post(url, data=data)`.","If you intended a plain form POST, pass `data=` only and omit `files` entirely.","If you must send an empty multipart body deliberately, construct it yourself with `urllib3.filepost.encode_multipart_formdata` and set the body/headers manually."],"exampleFix":"# before\nfiles = collect_uploads()  # may be {}\nresp = requests.post(url, files=files)\n\n# after\nfiles = collect_uploads()\nif files:\n    resp = requests.post(url, files=files)\nelse:\n    resp = requests.post(url, data=form_data)","handlingStrategy":"validation","validationCode":"# _encode_files raises when files is empty/None\nif not files:\n    raise ValueError(\"no files to upload\")  # or just call requests without files=\nresp = requests.post(url, files=files, data=data)","typeGuard":null,"tryCatchPattern":"try:\n    resp = requests.post(url, files=files)\nexcept ValueError as e:\n    if \"Files must be provided\" in str(e):\n        ...  # caller passed empty files mapping\n    raise","preventionTips":["Only pass the files= kwarg when you actually have files; omit it entirely for plain form posts","Check `if files:` before building a multipart request","Don't pass an empty dict/list as files= — requests treats that as a programming error"],"tags":["python","requests","multipart","file-upload","validation"],"analyzedSha":"414f0513c33883adf6f2b46901d4f0b38a455851","analyzedAt":"2026-07-31T19:24:57.696Z","schemaVersion":2}