{"record":{"id":"73040d0f8c9860ba","repo":"block/buzz","slug":"media-upload-failed","errorCode":null,"errorMessage":"Media upload failed.","messagePattern":"Media upload failed\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"desktop/src/shared/api/tauriMedia.ts","lineNumber":53,"sourceCode":"      \"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\n/** Release the renderer's cancellation ownership after an upload settles. */\nexport async function releaseMediaUpload(progressId: string): Promise<void> {\n  await invokeTauri(\"release_media_upload\", { progressId });\n}\n\n/**\n * Open a native single-file picker constrained to images and upload the\n * chosen file. Non-image files are rejected in Rust (via MIME sniffing)\n * before the bytes leave the client, so discarded/non-image selections never\n * reach the relay. Resolves to `null` when the user cancels the dialog.","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/block/buzz/blob/dad5a33865fc81a2e55b3b60746632f615ec1e3a/desktop/src/shared/api/tauriMedia.ts#L35-L71","documentation":"Fallback branch of uploadMediaFile's error normalization: when the IPC rejection is neither an Error, a non-empty string, nor an object with a usable `message`, it throws the generic 'Media upload failed.' The real cause is unknowable from the thrown value alone.","triggerScenarios":"upload_media_bytes_raw rejects with an empty string, null/undefined, a number, or an object without a message field — the native layer failed without a descriptive payload.","commonSituations":"Native HTTP stack crashing without text; unexpected plugin response shape; device offline with a terse rejection; progress IPC channel torn down mid-upload.","solutions":["Check the native/Tauri logs (devtools console, system log) for the underlying failure around the upload time.","Verify network connectivity and media server reachability from the device.","Confirm the Tauri media plugin/command versions match the frontend invoke signature.","Wrap invokeTauriRaw calls to log the raw rejection before normalization so future failures aren't opaque."],"exampleFix":"// before\n} catch (error) {\n  throw new Error(\"Media upload failed.\");\n}\n// after\n} catch (error) {\n  console.error(\"upload_media_bytes_raw rejection:\", error);\n  throw new Error(`Media upload failed: ${JSON.stringify(error)}`);\n}","handlingStrategy":"try-catch","validationCode":"if (!navigator.onLine) throw new Error('Offline: upload deferred');\n","typeGuard":"function isGenericUploadFailure(e: unknown): boolean { return e instanceof Error && e.message === 'Media upload failed.'; }\n","tryCatchPattern":"try { await uploadMediaFile(file); } catch (e) { if (isGenericUploadFailure(e)) showRetryDialog(file); else throw e; }\n","preventionTips":["Log raw IPC rejections before normalization for diagnosability","Check native/Tauri logs when the message is generic","Verify network reachability before upload and offer retry"],"tags":["upload","tauri","opaque-error"],"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"}