{"record":{"id":"b832c3fe90a06773","repo":"ComposioHQ/composio","slug":"error-downloading-file-sanitize-url-for-logging-b832c3","errorCode":null,"errorMessage":"Error downloading file: {_sanitize_url_for_logging(self.s3url)}","messagePattern":"Error downloading file: (.+?)","errorType":"exception","errorClass":"ErrorDownloadingFile","httpStatus":null,"severity":"error","filePath":"python/composio/core/models/_files.py","lineNumber":728,"sourceCode":"        # (sibling-prefix attack) is rejected too.\n        try:\n            outfile = secure_basename_join(outdir, self.name, root=root)\n        except UnsafePathComponentError as e:\n            raise ErrorDownloadingFile(str(e)) from e\n        try:\n            response = safe_get(\n                self.s3url,\n                stream=True,\n                timeout=(_CONNECT_TIMEOUT, _READ_TIMEOUT),\n            )\n        except requests.exceptions.RequestException as e:\n            raise ErrorDownloadingFile(\n                \"Error downloading file: \"\n                f\"{_sanitize_url_for_logging(self.s3url)}. Error: {type(e).__name__}\"\n            ) from e\n        if response.status_code != 200:\n            response.close()\n            raise ErrorDownloadingFile(\n                f\"Error downloading file: {_sanitize_url_for_logging(self.s3url)}\"\n            )\n\n        # Early abort for a self-declared oversized body. The header is only a\n        # hint — `parse_content_length` returns None for anything untrustworthy\n        # and the streaming counter below is the authoritative limit.\n        content_length = parse_content_length(response.headers.get(\"Content-Length\"))\n        if content_length is not None and content_length > max_size:\n            response.close()\n            raise ResponseTooLargeError(\n                f\"File size ({content_length} bytes) exceeds maximum allowed \"\n                f\"size ({max_size} bytes)\"\n            )\n\n        total_bytes = 0\n        try:\n            # Only once the fetch is validated and connected, so a blocked URL\n            # leaves no directory behind — and inside the `try`, so a failure","sourceCodeStart":710,"sourceCodeEnd":746,"githubUrl":"https://github.com/ComposioHQ/composio/blob/64b1b85502b1beeb2379e6c9e8bf1104504fa637/python/composio/core/models/_files.py#L710-L746","documentation":"The download GET completed but returned a non-200 status. Since presigned S3 URLs are short-lived, the most common cause is an expired or already-consumed URL; other 4xx/5xx indicate missing permissions or origin issues. Only the sanitized URL is shown.","triggerScenarios":"Calling FileModel.download on a model whose s3url presigned link has expired (issued long before), was single-use and already consumed, or the signature no longer matches. Also origin 5xx errors.","commonSituations":"Holding FileModel objects for a long time before downloading; retrying after a partial download that consumed the one-time URL; clock skew; bucket policy changes.","solutions":["Re-fetch a fresh FileModel (re-request the file/output from the API) so a new presigned URL is issued, then download promptly.","Download soon after obtaining the model rather than caching it long-term.","Check system clock sync (NTP) since signature windows are time-based.","If persistent, verify bucket/permission changes with Composio support."],"exampleFix":"# before\nmodel = get_model_now()\n# ... hours later ...\nmodel.download()  # non-200: expired presigned URL\n# after\nmodel = get_model_now()  # fresh model -> fresh presigned URL\nmodel.download()          # download immediately","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"from composio.core.models._files import ErrorDownloadingFile\n\ntry:\n    path = model.download()\nexcept ErrorDownloadingFile as e:\n    model = refresh_model(model.id)  # re-fetch -> fresh presigned URL\n    path = model.download()","preventionTips":["Download immediately after obtaining a FileModel; don't cache models with s3url for long periods.","On failure, re-request the model rather than retrying the same URL.","Keep server clocks NTP-synced to avoid signature-window issues."],"tags":["python","s3","download","presigned-url","expired"],"backgroundTag":"presigned-url-expired","analyzedSha":"64b1b85502b1beeb2379e6c9e8bf1104504fa637","analyzedAt":"2026-08-28T15:39:33.623Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}