ComposioHQ/composio · error · ErrorDownloadingFile

Error downloading file: {_sanitize_url_for_logging(self.s3ur

Error message

Error downloading file: {_sanitize_url_for_logging(self.s3url)}

What it means

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.

Source

Thrown at python/composio/core/models/_files.py:728

        # (sibling-prefix attack) is rejected too.
        try:
            outfile = secure_basename_join(outdir, self.name, root=root)
        except UnsafePathComponentError as e:
            raise ErrorDownloadingFile(str(e)) from e
        try:
            response = safe_get(
                self.s3url,
                stream=True,
                timeout=(_CONNECT_TIMEOUT, _READ_TIMEOUT),
            )
        except requests.exceptions.RequestException as e:
            raise ErrorDownloadingFile(
                "Error downloading file: "
                f"{_sanitize_url_for_logging(self.s3url)}. Error: {type(e).__name__}"
            ) from e
        if response.status_code != 200:
            response.close()
            raise ErrorDownloadingFile(
                f"Error downloading file: {_sanitize_url_for_logging(self.s3url)}"
            )

        # Early abort for a self-declared oversized body. The header is only a
        # hint — `parse_content_length` returns None for anything untrustworthy
        # and the streaming counter below is the authoritative limit.
        content_length = parse_content_length(response.headers.get("Content-Length"))
        if content_length is not None and content_length > max_size:
            response.close()
            raise ResponseTooLargeError(
                f"File size ({content_length} bytes) exceeds maximum allowed "
                f"size ({max_size} bytes)"
            )

        total_bytes = 0
        try:
            # Only once the fetch is validated and connected, so a blocked URL
            # leaves no directory behind — and inside the `try`, so a failure

View on GitHub (pinned to 64b1b85502)

Solutions

  1. Re-fetch a fresh FileModel (re-request the file/output from the API) so a new presigned URL is issued, then download promptly.
  2. Download soon after obtaining the model rather than caching it long-term.
  3. Check system clock sync (NTP) since signature windows are time-based.
  4. If persistent, verify bucket/permission changes with Composio support.

Example fix

# before
model = get_model_now()
# ... hours later ...
model.download()  # non-200: expired presigned URL
# after
model = get_model_now()  # fresh model -> fresh presigned URL
model.download()          # download immediately
Defensive patterns

Strategy: retry

Try / catch

from composio.core.models._files import ErrorDownloadingFile

try:
    path = model.download()
except ErrorDownloadingFile as e:
    model = refresh_model(model.id)  # re-fetch -> fresh presigned URL
    path = model.download()

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of ComposioHQ/composio@64b1b85502 (2026-08-28). Data as JSON: /api/errors/b832c3fe90a06773. Report an issue: GitHub.