ComposioHQ/composio · error · ToolFileUploadError
Failed to fetch file: ${response.statusText}
Error message
Failed to fetch file: ${response.statusText} What it means
When an upload source is a URL, readFileFromUrl fetches it and throws ToolFileUploadError with reason 'source-fetch' if the HTTP response is not ok, embedding the statusText (e.g. 'Not Found', 'Forbidden').
Source
Thrown at ts/packages/cli/src/services/tool-file-uploads.ts:148
isSchemaRecord(item) ? findFileUploadablePaths(item, basePath) : []
)
: isSchemaRecord(schema.items)
? findFileUploadablePaths(schema.items, basePath)
: [];
const seen = new Set<string>();
return [...directPropertyPaths, ...variantPaths, ...itemPaths].filter(pathParts => {
const key = pathParts.join('.');
if (seen.has(key)) return false;
seen.add(key);
return true;
});
};
const readFileFromUrl = async (path: Path.Path, url: string) => {
const response = await fetch(url);
if (!response.ok) {
throw new ToolFileUploadError({
message: `Failed to fetch file: ${response.statusText}`,
reason: 'source-fetch',
status: response.status,
});
}
const bytes = new Uint8Array(await response.arrayBuffer());
const parsedUrl = new URL(url);
const fileName = path.basename(parsedUrl.pathname) || `file-${Date.now()}`;
return {
bytes,
fileName,
mimeType: response.headers.get('content-type') || 'application/octet-stream',
};
};
// Runs the FileSystem read to completion for the plain-async pipeline above.View on GitHub (pinned to 64b1b85502)
Solutions
- Verify the URL opens in a browser/curl with the same anonymity (no auth)
- If the link is presigned and expired, generate a fresh one
- Add retry with backoff for transient 5xx before starting the upload flow
- Download manually and pass the local file path instead of the URL
Example fix
# before composio ... --file https://example.com/expired-presigned-url # after curl -I <url> # confirm 200 composio ... --file ./downloaded-file.pdf
Defensive patterns
Strategy: retry
Validate before calling
const ok = await fetch(url, { method: 'HEAD' }).then(r => r.ok).catch(() => false);
if (!ok) throw new Error('source URL unreachable'); Try / catch
catch (e) { if (e instanceof ToolFileUploadError && e.reason === 'source-fetch') { await backoff(); retryUpload(); } throw e; } Prevention
- Verify URLs with curl before batch runs
- Refresh presigned links at use time
- Fall back to a local file path when the URL is flaky
When it happens
Trigger: Passing a URL as the file source where the server returns 4xx/5xx: expired presigned link, private file requiring auth, 404 from a typo'd path, or a server-side 5xx.
Common situations: Presigned S3 URLs past their expiry, links requiring headers/cookies the plain fetch does not send, typo'd or deleted files, or transient upstream outages.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- Failed to fetch file: ${response.statusText}
- proxy fetch requires a non-empty URL string or URL object.
- Refusing to upload: {reason}. Set sensitive_file_upload_prot
- Refusing to auto-upload "{attempted}": the file does not exi
- Refusing to auto-upload "{attempted}": no upload directories
AI-assisted analysis of ComposioHQ/composio@64b1b85502 (2026-08-28).
Data as JSON: /api/errors/62c938a8a19bdf47.
Report an issue: GitHub.