{"record":{"id":"1dbcf8ed1b12d2cf","repo":"psf/requests","slug":"files-must-be-provided","errorCode":null,"errorMessage":"Files must be provided.","messagePattern":"Files must be provided\\.","errorType":"exception","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/8068356288978c4f54661ae6f95afe0e0831885e/src/requests/models.py#L177-L213","documentation":"Raised by Request._encode_files (the multipart/form-data body builder) when the files argument is empty or None. Multipart encoding is only meaningful when at least one file is supplied; an empty files dict usually indicates the caller reached the multipart path by mistake. The guard fails fast rather than emitting a malformed body.","triggerScenarios":"Calling requests.post(url, files={}) or files=None; building the files dict conditionally and the condition evaluated to empty; passing a dict comprehension that filters down to zero entries.","commonSituations":"Optional file-upload UIs where the user attached nothing but the request code still takes the files= branch; dynamically-built upload payloads where all attachments were filtered out by validation.","solutions":["Guard the files= argument: only pass it when the dict/list is non-empty (if files: requests.post(..., files=files) else: requests.post(...)).","If your intent is form data with no files, use the data= argument instead of files=.","Initialize files with a sentinel and skip the request entirely if no attachments were collected."],"exampleFix":"// before\nfiles = {k: v for k, v in uploads if v}\nrequests.post(url, files=files)\n\n// after\nfiles = {k: v for k, v in uploads if v}\nif files:\n    requests.post(url, files=files)\nelse:\n    requests.post(url)","handlingStrategy":"validation","validationCode":"def post_with_optional_files(url, files=None, **kw):\n    if files:\n        return requests.post(url, files=files, **kw)\n    return requests.post(url, **kw)","typeGuard":"from typing import Mapping, Any\n\ndef has_files(files) -> bool:\n    return bool(files) and (len(files) > 0)","tryCatchPattern":"# ValueError('Files must be provided.') indicates a logic bug; prefer to fix the caller.\n# Defensive form:\nif not files:\n    raise ValueError('no files to upload')\nrequests.post(url, files=files)","preventionTips":["Only pass files= when the collection is non-empty.","Use data= for form fields when no attachments are present.","Gate upload code behind an explicit 'if attachments' branch."],"tags":["upload","multipart","files","valueerror","validation"],"backgroundTag":null,"analyzedSha":"8068356288978c4f54661ae6f95afe0e0831885e","analyzedAt":"2026-08-11T20:11:09.238Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}