{"record":{"id":"d20a072126922ef6","repo":"ComposioHQ/composio","slug":"url-returned-redirect-please-provide-a-direct-url","errorCode":null,"errorMessage":"URL returned redirect. Please provide a direct URL to the file.","messagePattern":"URL returned redirect\\. Please provide a direct URL to the file\\.","errorType":"validation","errorClass":"ValidationError","httpStatus":null,"severity":"error","filePath":"python/composio/core/models/tool_router_session_files.py","lineNumber":148,"sourceCode":"                    size_detail=\"Response size exceeds maximum allowed size\"\n                )\n            chunks.append(chunk)\n    response.close()\n\n    mimetype = response.headers.get(\"content-type\", \"application/octet-stream\")\n    mimetype = mimetype.split(\";\")[0].strip()\n    return b\"\".join(chunks), mimetype\n\n\ndef _fetch_from_url(url: str) -> t.Tuple[bytes, str]:\n    \"\"\"Fetch file content from a user-supplied URL. Returns (content, mimetype).\"\"\"\n    try:\n        return _fetch_url_bytes(url)\n    except _UrlFetchError as e:\n        if e.cause is not None:\n            raise ValidationError(f\"Failed to fetch file from URL: {e.cause}\") from e\n        if e.redirected:\n            raise ValidationError(\n                \"URL returned redirect. Please provide a direct URL to the file.\"\n            ) from e\n        if e.status_code is not None:\n            raise ValidationError(\n                f\"Failed to fetch file from URL: {e.status_code} {e.status_text}\"\n            ) from e\n        raise ValidationError(str(e)) from e\n\n\nclass RemoteFile:\n    \"\"\"Represents a file stored in a tool router session's file mount.\n\n    Provides methods to fetch, save, and work with the file content.\n    \"\"\"\n\n    def __init__(\n        self,\n        *,","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/ComposioHQ/composio/blob/64b1b85502b1beeb2379e6c9e8bf1104504fa637/python/composio/core/models/tool_router_session_files.py#L130-L166","documentation":"The URL fetcher refuses to follow redirects when downloading a file for upload — if the server responds with a redirect status, this ValidationError tells you to supply the final direct URL. This avoids ambiguous/looping redirects and matches strict fetch behavior.","triggerScenarios":"Passing links that 30x-redirect: Google Drive share links, Dropbox ?dl=0 pages, S3 presigned URLs that redirect to another region host, shortlinks.","commonSituations":"Copy-pasting sharing URLs from cloud drives instead of direct-download links.","solutions":["Resolve the redirect yourself first (curl -sIL -o /dev/null -w '%{url_effective}') and pass the final URL","Use the direct-download variant (e.g. Dropbox ?dl=1, Drive export=download links)","Download locally and upload the bytes/path instead"],"exampleFix":"# before\nfiles.add(url='https://www.dropbox.com/s/abc/file.pdf?dl=0')\n\n# after\nfiles.add(url='https://www.dropbox.com/s/abc/file.pdf?dl=1')\n# or resolve final URL via HEAD and pass that","handlingStrategy":"validation","validationCode":"import requests\nr = requests.head(url, allow_redirects=False)\nif r.is_redirect:\n    url = r.headers['Location']  # resolve once, then pass final URL","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use direct-download links (dl=1, export=download)","Resolve redirects before passing URLs"],"tags":["python","files","upload","redirect","url-fetch"],"backgroundTag":"url-redirect-not-followed","analyzedSha":"64b1b85502b1beeb2379e6c9e8bf1104504fa637","analyzedAt":"2026-08-28T15:39:33.623Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}