{"id":"f86ed6905d7e9161","repo":"psf/requests","slug":"you-can-only-send-preparedrequests","errorCode":null,"errorMessage":"You can only send PreparedRequests.","messagePattern":"You can only send PreparedRequests\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/requests/sessions.py","lineNumber":768,"sourceCode":"        return self.request(\"DELETE\", url, **kwargs)\n\n    def send(self, request: PreparedRequest, **kwargs: Any) -> Response:\n        \"\"\"Send a given PreparedRequest.\n\n        :rtype: requests.Response\n        \"\"\"\n        # Set defaults that the hooks can utilize to ensure they always have\n        # the correct parameters to reproduce the previous request.\n        kwargs.setdefault(\"stream\", self.stream)\n        kwargs.setdefault(\"verify\", self.verify)\n        kwargs.setdefault(\"cert\", self.cert)\n        if \"proxies\" not in kwargs:\n            kwargs[\"proxies\"] = resolve_proxies(request, self.proxies, self.trust_env)\n\n        # It's possible that users might accidentally send a Request object.\n        # Guard against that specific failure case.\n        if isinstance(request, Request):\n            raise ValueError(\"You can only send PreparedRequests.\")\n\n        assert _is_prepared(request)\n\n        # Set up variables needed for resolve_redirects and dispatching of hooks\n        allow_redirects = kwargs.pop(\"allow_redirects\", True)\n        stream = kwargs.get(\"stream\")\n        hooks = request.hooks\n\n        # Get the appropriate adapter to use\n        adapter = self.get_adapter(url=request.url)\n\n        # Start time (approximately) of the request\n        start = preferred_clock()\n\n        # Send the request\n        r = adapter.send(request, **kwargs)\n\n        # Total elapsed time of the request (approximately)","sourceCodeStart":750,"sourceCodeEnd":786,"githubUrl":"https://github.com/psf/requests/blob/414f0513c33883adf6f2b46901d4f0b38a455851/src/requests/sessions.py#L750-L786","documentation":"Raised as a plain `ValueError` from `Session.send()` in `src/requests/sessions.py:768`. `Session.send()` transmits an already-prepared request; it guards against being handed a raw `requests.Request` (which lacks a URL-encoded body, merged headers, and cookies) because the two types are easy to confuse. The public API path is `Session.request()`/`requests.get()` etc., which prepare the request for you.","triggerScenarios":"Calling `session.send(req)` where `req = requests.Request('GET', url)` was never passed through `session.prepare_request(req)` or `req.prepare()`. Common in code using the prepared-request pattern for header inspection, custom auth signing, or test frameworks that build Request objects manually.","commonSituations":"Following the prepared-request docs but skipping the `prepare_request()` step; refactors that changed a variable from the prepared to the raw request; middleware/instrumentation that intercepts and re-sends requests; mocking layers that hand back a Request instead of a PreparedRequest.","solutions":["Prepare the request first: `prepped = session.prepare_request(req); resp = session.send(prepped)` — prefer `session.prepare_request` over `req.prepare()` so session cookies/headers merge.","If you don't need the prepared-request pattern, call `session.request('GET', url, ...)` or `requests.get(url)` instead of `send()`."],"exampleFix":"# before\nreq = requests.Request('GET', url, headers=h)\nresp = session.send(req)\n# after\nreq = requests.Request('GET', url, headers=h)\nprepped = session.prepare_request(req)\nresp = session.send(prepped)","handlingStrategy":"type-guard","validationCode":"from requests import Request, PreparedRequest\nreq = Request('GET', url).prepare()  # prepare() before session.send()\nassert isinstance(req, PreparedRequest)","typeGuard":"from requests import PreparedRequest\ndef is_prepared(req):\n    return isinstance(req, PreparedRequest)","tryCatchPattern":"try:\n    resp = session.send(req)\nexcept ValueError as e:\n    if 'PreparedRequests' in str(e):\n        resp = session.send(session.prepare_request(req))\n    else:\n        raise","preventionTips":["Call session.prepare_request(request) (or request.prepare()) before session.send() — send() only accepts PreparedRequest","Prefer the high-level session.get/post/request methods unless you specifically need the prepare/send split","Type-annotate helper functions that pass requests around (req: PreparedRequest) so mypy catches the mixup"],"tags":["session","prepared-request","api-misuse","python","requests"],"analyzedSha":"414f0513c33883adf6f2b46901d4f0b38a455851","analyzedAt":"2026-07-31T19:24:57.696Z","schemaVersion":2}