{"record":{"id":"051c73359ce07cd1","repo":"ComposioHQ/composio","slug":"failed-to-fetch-file-from-url-e-status-code-e","errorCode":null,"errorMessage":"Failed to fetch file from URL: {e.status_code} {e.status_text}","messagePattern":"Failed to fetch file from URL: (.+?) (.+?)","errorType":"validation","errorClass":"ValidationError","httpStatus":null,"severity":"error","filePath":"python/composio/core/models/tool_router_session_files.py","lineNumber":152,"sourceCode":"\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        *,\n        expires_at: str,\n        mount_relative_path: str,\n        sandbox_mount_prefix: str,\n        download_url: str,","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/ComposioHQ/composio/blob/64b1b85502b1beeb2379e6c9e8bf1104504fa637/python/composio/core/models/tool_router_session_files.py#L134-L170","documentation":"Raised when the URL fetch for a file upload returns a non-success HTTP status (4xx/5xx). The status code and reason text are included, so auth failures (401/403), missing objects (404), and server errors are distinguishable in the message.","triggerScenarios":"Passing an expired pre-signed URL (403), a deleted file (404), or a link behind authentication (401) to the by-URL upload API.","commonSituations":"Pre-signed S3/GCS URLs past their expiry, links requiring cookies/login, rate-limited endpoints (429).","solutions":["Check the code in the message: 403 → regenerate the presigned URL; 404 → object deleted/moved; 429 → back off and retry","Refresh the link generation and re-upload","Fall back to direct byte/path upload if the URL keeps failing"],"exampleFix":"# before\nfiles.add(url=expired_presigned_s3_url)\n\n# after\nfresh = generate_presigned_url(bucket, key, expires=3600)\nfiles.add(url=fresh)","handlingStrategy":"retry","validationCode":"import requests\nr = requests.head(url)\nassert r.status_code == 200, f'URL returned {r.status_code}'","typeGuard":null,"tryCatchPattern":"try:\n    files.add(url=url)\nexcept ValidationError as e:\n    if '403' in str(e):\n        url = refresh_presigned_url(); files.add(url=url)\n    else:\n        raise","preventionTips":["Use long-expiry presigned URLs","Verify link with HEAD before upload"],"tags":["python","files","upload","http-status","url-fetch"],"backgroundTag":"http-error-status","analyzedSha":"64b1b85502b1beeb2379e6c9e8bf1104504fa637","analyzedAt":"2026-08-28T15:39:33.623Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}