{"record":{"id":"c487b9a390c6f9f8","repo":"block/buzz","slug":"media-fetch-cancelled","errorCode":null,"errorMessage":"Media fetch cancelled","messagePattern":"Media fetch cancelled","errorType":"exception","errorClass":"DOMException","httpStatus":null,"severity":"info","filePath":"desktop/src/shared/api/tauriMedia.ts","lineNumber":90,"sourceCode":" */\nexport async function pickAndUploadImage(): Promise<BlobDescriptor | null> {\n  return invokeTauri<BlobDescriptor | null>(\"pick_and_upload_image\", {});\n}\n\n/**\n * Fetch relay media bytes over IPC (Rust reqwest, VPN-tunneled).\n *\n * Used by the composer image editor: wrapping the bytes in a same-origin\n * `blob:` URL gives the canvas pixel access without CORS, so the media\n * proxy needs no special headers. The Rust side enforces the same URL\n * validation and size cap as the download commands.\n */\nexport async function fetchMediaBytes(\n  url: string,\n  signal?: AbortSignal,\n): Promise<Uint8Array<ArrayBuffer>> {\n  if (signal?.aborted) {\n    throw new DOMException(\"Media fetch cancelled\", \"AbortError\");\n  }\n\n  const requestId = signal ? crypto.randomUUID() : undefined;\n  // The Rust command replies with `tauri::ipc::Response`, so the bytes\n  // arrive as a raw ArrayBuffer rather than a JSON number array.\n  const request = invokeTauri<ArrayBuffer>(\"fetch_media_bytes\", {\n    requestId,\n    url,\n  });\n  if (!signal || !requestId) return new Uint8Array(await request);\n\n  let rejectCancellation: ((reason?: unknown) => void) | undefined;\n  const cancellation = new Promise<never>((_resolve, reject) => {\n    rejectCancellation = reject;\n  });\n  const onAbort = () => {\n    void invokeTauri(\"cancel_media_fetch\", { requestId })\n      .catch(() => undefined)","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/block/buzz/blob/dad5a33865fc81a2e55b3b60746632f615ec1e3a/desktop/src/shared/api/tauriMedia.ts#L72-L108","documentation":"fetchMediaBytes downloads media bytes via the Tauri command `fetch_media_bytes` and accepts an optional AbortSignal for cancellation. If the signal is already aborted at entry, it throws a DOMException AbortError named 'Media fetch cancelled' instead of making the IPC call. This is intentional fast-fail semantics so callers can treat it uniformly with mid-flight cancellations.","triggerScenarios":"Calling fetchMediaBytes (directly or via load/bytes helpers) with an AbortSignal that has already been aborted — e.g. a component unmounted before the download started, or a race where abort() fires between scheduling the call and entering the function.","commonSituations":"React effect cleanup aborts a controller before the async media fetch begins; a user closes an attachment viewer while its media is queued; parallel loads share one controller and one completes first.","solutions":["Check signal.aborted before calling fetchMediaBytes and skip the call if already aborted","Create a fresh AbortController per fetch instead of reusing a shared one that may already be aborted","Catch AbortError (e.name === 'AbortError') and treat it as a benign no-op rather than logging it as a failure"],"exampleFix":"// before\nconst bytes = await fetchMediaBytes(url, controller.signal);\n// after\nif (controller.signal.aborted) return;\ntry {\n  const bytes = await fetchMediaBytes(url, controller.signal);\n} catch (e) {\n  if ((e as DOMException).name === 'AbortError') return; // benign cancellation\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"if (signal?.aborted) return; // skip the fetch entirely","typeGuard":"function isAbortError(e: unknown): e is DOMException {\n  return e instanceof DOMException && e.name === 'AbortError';\n}","tryCatchPattern":"try {\n  const bytes = await fetchMediaBytes(url, signal);\n} catch (e) {\n  if (isAbortError(e)) return null; // benign cancellation\n  throw e;\n}","preventionTips":["Create one AbortController per fetch lifecycle, not shared across loads","Check signal.aborted before initiating any async work","Never log AbortError as an error — filter it in catch blocks"],"tags":["abort","cancellation","tauri","media"],"backgroundTag":"abort-error-cancellation","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"}