ComposioHQ/composio · error · Error
Failed to upload file: ${uploadResponse.statusText}
Error message
Failed to upload file: ${uploadResponse.statusText} What it means
After obtaining a presigned upload URL, the SDK performs a raw fetch PUT of the file bytes. If the storage endpoint responds with a non-2xx status, a generic Error with the response statusText is thrown. This usually indicates the presigned URL was rejected, expired, or the request was malformed at the object-storage layer, not the Composio API layer.
Source
Thrown at ts/packages/core/src/models/ToolRouterSessionFileMount.ts:258
? (createUploadURLResponse as { body: unknown }).body
: createUploadURLResponse;
// SSRF guard: `upload_url` comes from the API response, so the target is
// validated before the file's bytes are sent to it — the same treatment the
// user-supplied URL above already gets. See ssrfGuard.node.ts.
const uploadResponse = await ssrfSafeFetchWhereSupported(
(uploadURLData as { upload_url: string }).upload_url,
{
method: 'PUT',
body: await fileToUpload.arrayBuffer(),
headers: {
'Content-Type': mimetype,
},
}
);
if (!uploadResponse.ok) {
throw new Error(`Failed to upload file: ${uploadResponse.statusText}`);
}
const createDownloadURLResponse = await this.client.toolRouter.session.files.createDownloadURL(
uploadOptions.data.mountId,
{
session_id: this.sessionId,
mount_relative_path: (uploadURLData as { mount_relative_path: string }).mount_relative_path,
}
);
const downloadData =
typeof createDownloadURLResponse === 'object' && 'body' in createDownloadURLResponse
? (createDownloadURLResponse as { body: unknown }).body
: createDownloadURLResponse;
const parsed = RemoteFileDataSchema.safeParse(downloadData);
if (!parsed.success) {
throw new ValidationError('Failed to parse remote file properties', {View on GitHub (pinned to 64b1b85502)
Solutions
- Retry the whole upload call so a fresh presigned URL is generated
- Ensure mimetype passed at upload matches what the URL was signed for (do not modify headers)
- Check network/proxy settings if uploads consistently fail
Example fix
// before
const remote = await mount.upload(file);
// after
let remote;
for (let i = 0; i < 3; i++) {
try { remote = await mount.upload(file); break; }
catch (e) { if (i === 2) throw e; await new Promise(r => setTimeout(r, 1000 * (i + 1))); }
} Defensive patterns
Strategy: retry
Try / catch
try { await mount.upload(file, opts); } catch (e) { if (e instanceof Error && e.message.startsWith('Failed to upload file:')) { /* retry with fresh URL */ } throw e; } Prevention
- Upload promptly after obtaining presigned URLs; don't cache them
- Don't override Content-Type or add headers to presigned PUTs
- Add exponential-backoff retry around uploads
When it happens
Trigger: PUT to the presigned URL returns non-ok: expired presigned URL (long delay between createUploadURL and the PUT), Content-Type mismatch with the signed headers, network/proxy interference, or corrupted/empty body.
Common situations: Slow networks where the upload starts after URL expiry, corporate proxies rewriting requests, retries that reuse a stale presigned URL, or a mismatched mimetype between signing and upload.
Related errors
- Failed to fetch file from URL: {e.cause}
- Failed to upload file to S3: ${uploadResponse.statusText}
- Failed to parse tool router session files mount upload optio
- Failed to parse remote file properties
- Failed to upload file to S3: ${uploadResponse.statusText}
AI-assisted analysis of ComposioHQ/composio@64b1b85502 (2026-08-28).
Data as JSON: /api/errors/793029139bb6bca8.
Report an issue: GitHub.