ComposioHQ/composio · error · Error
Failed to download file: ${response.statusText}
Error message
Failed to download file: ${response.statusText} What it means
downloadFileFromS3 fetches the s3Url from a tool-execution response via ssrfSafeFetch; a non-OK status throws with the status text. The body would be streamed to disk, so it is size-limited but the error path occurs before that.
Source
Thrown at ts/packages/core/src/utils/fileUtils.node.ts:365
mimeType: string;
/**
* Absolute path to the directory to save the file into. When omitted, falls
* back to `<home>/.composio/files` (the legacy default).
*/
fileDownloadDir?: string;
signal?: AbortSignal;
/**
* Maximum number of bytes to read from the response before rejecting.
* Defaults to {@link MAX_URL_UPLOAD_SIZE_BYTES} (100 MiB).
*/
maxDownloadBytes?: number;
}): Promise<FileDownloadData> => {
// SSRF guard: `s3Url` is a field of the tool-execution response, so it is no
// more trusted than a user-supplied URL — and the bytes it returns are
// written to disk. See ssrfGuard.node.ts.
const response = await ssrfSafeFetch(s3Url, { signal });
if (!response.ok) {
throw new Error(`Failed to download file: ${response.statusText}`);
}
// The response is attacker-influencable and streamed to disk, so the body is
// read through the shared size guard rather than buffered wholesale.
const data = await readResponseBodyWithLimit(response, maxDownloadBytes);
const extension = getExtensionFromMimeType(mimeType);
const fileName = generateTimestampedFilename(extension, `${toolSlug}_`);
const filePath = saveFile(fileName, data, {
isTempFile: fileDownloadDir === undefined,
outputDir: fileDownloadDir,
});
return {
name: fileName,
mimeType: mimeType,
s3Url: s3Url,
/**
* @todo: fix in follow-up PR.View on GitHub (pinned to 64b1b85502)
Solutions
- Re-execute the tool or re-request the download URL to get a fresh signed link.
- Retry with backoff for transient 5xx.
- Inspect the s3Url manually with curl to see the exact status.
Defensive patterns
Strategy: retry
Try / catch
try { await downloadFileFromS3(url, {...}); } catch (e) {
if ((e as Error).message.startsWith('Failed to download file:')) { /* refresh url / re-execute tool */ }
} Prevention
- Download result files promptly after execution.
- Retry transient S3 5xx with backoff.
When it happens
Trigger: A tool execution returns an s3Url that is expired (403 S3 signature), deleted (404), or the host returns 5xx during file download.
Common situations: Downloading tool output files long after execution finished, cross-region S3 issues, or backend-generated URLs with short TTLs.
Related errors
- Error downloading file: {_sanitize_url_for_logging(self.s3ur
- Failed to upload file to S3: ${uploadResponse.statusText}
- Error downloading file: {_sanitize_url_for_logging(self.s3ur
- Failed to download file: {message} (status_code, status_text
- Failed to upload file to S3: ${uploadResponse.statusText}
AI-assisted analysis of ComposioHQ/composio@64b1b85502 (2026-08-28).
Data as JSON: /api/errors/038c16ecf5cad900.
Report an issue: GitHub.