{"record":{"id":"453d7bf1ebc76bce","repo":"CopilotKit/CopilotKit","slug":"whatsapp-uploadmedia-failed-res-status-await","errorCode":null,"errorMessage":"WhatsApp uploadMedia failed: ${res.status} ${await safeText(res)}","messagePattern":"WhatsApp uploadMedia failed: (.+?) (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/channels-whatsapp/src/client.ts","lineNumber":122,"sourceCode":"      \"file\",\n      new Blob(\n        [\n          (bytes.buffer as ArrayBuffer).slice(\n            bytes.byteOffset,\n            bytes.byteOffset + bytes.byteLength,\n          ),\n        ],\n        { type: mimeType },\n      ),\n      filename,\n    );\n    const res = await this.fetchImpl(url, {\n      method: \"POST\",\n      headers: this.authHeader,\n      body: form,\n    });\n    if (!res.ok)\n      throw new Error(\n        `WhatsApp uploadMedia failed: ${res.status} ${await safeText(res)}`,\n      );\n    const json = (await res.json()) as { id?: string };\n    if (!json.id) throw new Error(\"WhatsApp uploadMedia returned no id\");\n    return json.id;\n  }\n\n  /** Resolve a media id to a download URL, then fetch the bytes. */\n  async downloadMedia(mediaId: string): Promise<DownloadedMedia> {\n    const metaUrl = `${this.base}/${this.apiVersion}/${mediaId}`;\n    const metaRes = await this.fetchImpl(metaUrl, { headers: this.authHeader });\n    if (!metaRes.ok)\n      throw new Error(`WhatsApp media meta failed: ${metaRes.status}`);\n    const meta = (await metaRes.json()) as { url?: string; mime_type?: string };\n    if (!meta.url) throw new Error(\"WhatsApp media meta returned no url\");\n    const blobRes = await this.fetchImpl(meta.url, {\n      headers: this.authHeader,\n    });","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/CopilotKit/CopilotKit/blob/68fbe97d87420bd84e8196965c71bd6e394a3f7a/packages/channels-whatsapp/src/client.ts#L104-L140","documentation":"Thrown when the WhatsApp Cloud API POST to /media returns a non-2xx status while uploading a file. The error message embeds the HTTP status code and the (truncated) response body via safeText, so the underlying cause (auth failure, unsupported media type, size limit) is visible in the message.","triggerScenarios":"Calling uploadMedia()/mediaId() with an invalid/expired access token (401), a media file whose type is not supported by WhatsApp (415), a file exceeding WhatsApp's media size limits (413), or a malformed phone-number-id in the base URL (404).","commonSituations":"Expired WhatsApp access token (they expire after 24h), wrong phone number ID after switching WhatsApp Business accounts, uploading unsupported formats, or hitting the 100MB/16MB media limits depending on type.","solutions":["Check the status code and body in the message: 401/403 means refresh the access token; 415 means convert the file to a supported type (images jpeg/png, audio ogg/opus, video mp4, documents pdf etc.)","Verify the phone number ID and API version used to build the client base URL","Reduce media file size below WhatsApp's documented limits for its type","Retry with backoff on 5xx/status 429 — transient Meta API errors"],"exampleFix":"// before\nconst id = await client.uploadMedia(bytes, \"image/heic\", \"photo.heic\");\n\n// after\n// convert unsupported format first\nconst id = await client.uploadMedia(bytes, \"image/jpeg\", \"photo.jpg\");","handlingStrategy":"try-catch","validationCode":"const SUPPORTED = new Set([\"image/jpeg\",\"image/png\",\"video/mp4\",\"audio/ogg\",\"application/pdf\" /* etc */]);\nif (!SUPPORTED.has(mimeType) || bytes.length > MAX_FOR_TYPE(mimeType)) throw new RangeError(\"unsupported media\");","typeGuard":"function isUploadableMedia(m: {bytes: Uint8Array; mimeType: string}): boolean {\n  return SUPPORTED_MIME.has(m.mimeType) && m.bytes.length > 0;\n}","tryCatchPattern":"try { const id = await client.uploadMedia(...); } catch (e) { if (e instanceof Error && e.message.startsWith(\"WhatsApp uploadMedia failed\")) { /* inspect status: 401 -> refresh token; 5xx/429 -> retry */ } throw e; }","preventionTips":["Validate mime type and size before uploading","Keep the access token fresh (fetch shortly before use)","Wrap uploads in retry-with-backoff for 429/5xx"],"tags":["whatsapp","media-upload","http-error","cloud-api"],"backgroundTag":"http-request-failed","analyzedSha":"68fbe97d87420bd84e8196965c71bd6e394a3f7a","analyzedAt":"2026-08-27T04:03:26.537Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}