{"record":{"id":"31f7b41060be12af","repo":"ComposioHQ/composio","slug":"failed-to-upload-file-to-s3-uploadresponse-stat","errorCode":null,"errorMessage":"Failed to upload file to S3: ${uploadResponse.statusText}","messagePattern":"Failed to upload file to S3: (.+?)","errorType":"exception","errorClass":"ToolFileUploadError","httpStatus":null,"severity":"error","filePath":"ts/packages/cli/src/services/tool-file-uploads.ts","lineNumber":262,"sourceCode":"  const presigned = await params.client.files.createPresignedURL({\n    filename: fileData.fileName,\n    mimetype: fileData.mimeType,\n    md5,\n    tool_slug: params.toolSlug,\n    toolkit_slug: params.toolkitSlug,\n  });\n\n  const uploadResponse = await fetch(presigned.new_presigned_url, {\n    method: 'PUT',\n    body: fileData.bytes,\n    headers: {\n      'Content-Type': fileData.mimeType,\n      'Content-Length': fileData.bytes.byteLength.toString(),\n    },\n  });\n\n  if (!uploadResponse.ok) {\n    throw new ToolFileUploadError({\n      message: `Failed to upload file to S3: ${uploadResponse.statusText}`,\n      reason: 'upload',\n      status: uploadResponse.status,\n    });\n  }\n\n  return {\n    name: fileData.fileName,\n    mimetype: fileData.mimeType,\n    s3key: presigned.key,\n  };\n};\n\nconst hydrateFileUploads = async (\n  value: unknown,\n  schema: JsonSchema | undefined,\n  ctx: {\n    readonly fs: FileSystem.FileSystem;","sourceCodeStart":244,"sourceCodeEnd":280,"githubUrl":"https://github.com/ComposioHQ/composio/blob/64b1b85502b1beeb2379e6c9e8bf1104504fa637/ts/packages/cli/src/services/tool-file-uploads.ts#L244-L280","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Retry the whole upload flow (fetch a fresh presigned URL) — most expiry/signature issues self-heal","Ensure Content-Type sent matches what was declared when the URL was generated; don't modify the file between steps","Reduce file size or chunk large uploads","Check S3 status (health.aws.amazon.com) for ongoing incidents"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"catch (e) { if (e instanceof ToolFileUploadError && e.reason === 'upload') { return await uploadFileFreshUrl(); /* re-request presigned URL and retry */ } throw e; }","preventionTips":["Upload immediately after obtaining the presigned URL","Keep Content-Type consistent between URL generation and PUT","Retry transient S3 5xx with backoff"],"tags":["file-upload","s3","presigned-url","network"],"backgroundTag":"presigned-url-upload-failed","analyzedSha":"64b1b85502b1beeb2379e6c9e8bf1104504fa637","analyzedAt":"2026-08-28T15:39:33.623Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}