{"record":{"id":"ae5d7d34a51d79ea","repo":"block/buzz","slug":"error","errorCode":null,"errorMessage":"${error}","messagePattern":"\\$\\{error\\}","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"desktop/src/shared/api/tauriMedia.ts","lineNumber":43,"sourceCode":"  if (progressId) {\n    headers[\"x-buzz-progress-id\"] = encodeRawIpcHeader(progressId);\n  }\n\n  if (signal?.aborted) throw new Error(\"upload cancelled\");\n  const bytes = new Uint8Array(await file.arrayBuffer());\n  if (signal?.aborted) throw new Error(\"upload cancelled\");\n  onDispatch?.();\n  try {\n    return await invokeTauriRaw<BlobDescriptor>(\n      \"upload_media_bytes_raw\",\n      bytes,\n      {\n        headers,\n      },\n    );\n  } catch (error) {\n    if (error instanceof Error) throw error;\n    if (typeof error === \"string\" && error.trim()) throw new Error(error);\n    if (\n      typeof error === \"object\" &&\n      error !== null &&\n      \"message\" in error &&\n      typeof error.message === \"string\" &&\n      error.message.trim()\n    ) {\n      throw new Error(error.message);\n    }\n    throw new Error(\"Media upload failed.\");\n  }\n}\n\n/** Stop the native HTTP request associated with a background media upload. */\nexport async function cancelMediaUpload(progressId: string): Promise<void> {\n  await invokeTauri(\"cancel_media_upload\", { progressId });\n}\n","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/block/buzz/blob/dad5a33865fc81a2e55b3b60746632f615ec1e3a/desktop/src/shared/api/tauriMedia.ts#L25-L61","documentation":"Tauri IPC rejections are not always Error instances; uploadMediaFile normalizes them. This throw re-raises a non-empty string rejection as a real Error with the backend's message as text. The literal message equals whatever string the Tauri command returned.","triggerScenarios":"upload_media_bytes_raw rejects with a bare string (Rust error serialized as a string) — e.g. native HTTP failure, server 4xx/5xx body, or IPC layer error text.","commonSituations":"Media server rejecting the upload (auth, size limit); Rust command returning Err(String); proxy/timeouts surfaced as raw strings by the Tauri plugin.","solutions":["Read error.message — it contains the native/backend error text and diagnose from there.","Check relay/media server logs for the matching failure (auth, quota, size).","Validate file size/type limits client-side before uploading.","Upgrade error handling to attach context (filename, progressId) when rethrowing."],"exampleFix":"// before\ncatch (e) { console.log(e); }\n// after\ncatch (e) {\n  const msg = e instanceof Error ? e.message : String(e);\n  throw new Error(`Media upload of ${file.name} failed: ${msg}`);\n}","handlingStrategy":"try-catch","validationCode":"if (file.size > MAX_UPLOAD_BYTES) throw new Error('File too large before upload');\n","typeGuard":"function isStringRejection(e: unknown): e is Error { return typeof e === 'string' && e.trim().length > 0; }\n","tryCatchPattern":"try { await uploadMediaFile(file); } catch (e) { const msg = e instanceof Error ? e.message : String(e); handleError(msg); }\n","preventionTips":["Validate size/type client-side before upload","Keep media server auth tokens fresh","Log error.message — it carries the backend text"],"tags":["upload","tauri","error-normalization"],"backgroundTag":"media-upload-failed","analyzedSha":"dad5a33865fc81a2e55b3b60746632f615ec1e3a","analyzedAt":"2026-09-05T18:13:50.666Z","contentChangedAt":"2026-09-05T18:13:50.666Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}