{"record":{"id":"4c0be6d10b07a6f0","repo":"ComposioHQ/composio","slug":"unsupported-upload-source","errorCode":null,"errorMessage":"Unsupported upload source","messagePattern":"Unsupported upload source","errorType":"validation","errorClass":"ToolFileUploadError","httpStatus":null,"severity":"error","filePath":"ts/packages/cli/src/services/tool-file-uploads.ts","lineNumber":226,"sourceCode":"  file: string | File\n) => {\n  if (isFileLike(file)) {\n    return {\n      bytes: new Uint8Array(await file.arrayBuffer()),\n      fileName: file.name || `file-${Date.now()}`,\n      mimeType: file.type || 'application/octet-stream',\n    };\n  }\n\n  if (typeof file === 'string' && /^https?:\\/\\//i.test(file)) {\n    return readFileFromUrl(path, file);\n  }\n\n  if (typeof file === 'string') {\n    return readFileFromDisk(fs, path, file);\n  }\n\n  throw new ToolFileUploadError({\n    message: 'Unsupported upload source',\n    reason: 'unsupported-source',\n  });\n};\n\nconst uploadFile = async (params: {\n  readonly fs: FileSystem.FileSystem;\n  readonly path: Path.Path;\n  readonly file: string | File;\n  readonly toolSlug: string;\n  readonly toolkitSlug: string;\n  readonly client: RawComposioClient;\n}) => {\n  const fileData = await readUploadSource(params.fs, params.path, params.file);\n  // eslint-disable-next-line no-restricted-imports -- MD5 for the presigned-upload checksum is not available in Web Crypto\n  const { createHash } = await import('node:crypto');\n  const md5 = createHash('md5').update(fileData.bytes).digest('hex');\n  const presigned = await params.client.files.createPresignedURL({","sourceCodeStart":208,"sourceCodeEnd":244,"githubUrl":"https://github.com/ComposioHQ/composio/blob/64b1b85502b1beeb2379e6c9e8bf1104504fa637/ts/packages/cli/src/services/tool-file-uploads.ts#L208-L244","documentation":"readUploadSource dispatches on the file argument's shape: Blob/File-like sources and plain strings (disk paths) are supported; anything else hits the terminal branch throwing ToolFileUploadError with reason 'unsupported-source'.","triggerScenarios":"Passing a file argument that is neither a Blob/File nor a string — e.g. a number, a plain object like { path: '...' }, a Buffer in an environment where it isn't recognized as a Blob, or null/undefined where a value is required.","commonSituations":"Wrapping the path in an object ({ path }) instead of passing the string, passing a Node Buffer where a Blob is expected, or a serialization step turning the File into a plain object.","solutions":["Pass the local file path as a plain string","Pass an actual Blob/File instance (e.g. new Blob([bytes])) — wrap Node Buffers: new Blob([buffer])","Do not wrap the source in an object; unwrap { path } to path"],"exampleFix":"// before\nupload({ file: { path: '/tmp/a.pdf' } });\n// after\nupload({ file: '/tmp/a.pdf' });\n// or\nupload({ file: new Blob([fs.readFileSync('/tmp/a.pdf')]) });","handlingStrategy":"type-guard","validationCode":"if (typeof file !== 'string' && !(file instanceof Blob)) throw new TypeError('file must be a path string or Blob');","typeGuard":"const isUploadSource = (v: unknown): v is string | Blob => typeof v === 'string' || (typeof Blob !== 'undefined' && v instanceof Blob);","tryCatchPattern":null,"preventionTips":["Never wrap paths in objects","Convert Buffers: new Blob([buffer], { type })","Type the upload parameter as string | Blob at the call site"],"tags":["file-upload","validation","type-mismatch"],"backgroundTag":"unsupported-argument-type","analyzedSha":"64b1b85502b1beeb2379e6c9e8bf1104504fa637","analyzedAt":"2026-08-28T15:39:33.623Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}