ComposioHQ/composio · error · ToolFileUploadError

Failed to upload file to S3: ${uploadResponse.statusText}

Error message

Failed to upload file to S3: ${uploadResponse.statusText}

What it means

After obtaining an upload URL, uploadFile PUTs the bytes to S3 with the file's Content-Type/Length. A non-ok upload response throws ToolFileUploadError with reason 'upload', including the S3 statusText.

Source

Thrown at ts/packages/cli/src/services/tool-file-uploads.ts:262

  const presigned = await params.client.files.createPresignedURL({
    filename: fileData.fileName,
    mimetype: fileData.mimeType,
    md5,
    tool_slug: params.toolSlug,
    toolkit_slug: params.toolkitSlug,
  });

  const uploadResponse = await fetch(presigned.new_presigned_url, {
    method: 'PUT',
    body: fileData.bytes,
    headers: {
      'Content-Type': fileData.mimeType,
      'Content-Length': fileData.bytes.byteLength.toString(),
    },
  });

  if (!uploadResponse.ok) {
    throw new ToolFileUploadError({
      message: `Failed to upload file to S3: ${uploadResponse.statusText}`,
      reason: 'upload',
      status: uploadResponse.status,
    });
  }

  return {
    name: fileData.fileName,
    mimetype: fileData.mimeType,
    s3key: presigned.key,
  };
};

const hydrateFileUploads = async (
  value: unknown,
  schema: JsonSchema | undefined,
  ctx: {
    readonly fs: FileSystem.FileSystem;

View on GitHub (pinned to 64b1b85502)

Solutions

  1. Retry the whole upload flow (fetch a fresh presigned URL) — most expiry/signature issues self-heal
  2. Ensure Content-Type sent matches what was declared when the URL was generated; don't modify the file between steps
  3. Reduce file size or chunk large uploads
  4. Check S3 status (health.aws.amazon.com) for ongoing incidents
Defensive patterns

Strategy: retry

Try / catch

catch (e) { if (e instanceof ToolFileUploadError && e.reason === 'upload') { return await uploadFileFreshUrl(); /* re-request presigned URL and retry */ } throw e; }

Prevention

When it happens

Trigger: The presigned PUT fails server-side: signature/expiry mismatch on the presigned URL, request-size limits, altered headers (Content-Type changed after URL generation), or an S3 5xx.

Common situations: Delay between getting the presigned URL and uploading past its expiry, mutating the file bytes or mime type in between, very large files exceeding the presigned policy, or transient S3 errors.

Related errors


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