{"record":{"id":"5a87827d277b2e61","repo":"tonhowtf/omniget","slug":"subtitle-save-error-surfaced-to-user-via-err-localized-toast","errorCode":null,"errorMessage":"subtitle_save error surfaced to user via err() (localized toast)","messagePattern":"subtitle_save error surfaced to user via err\\(\\) \\(localized toast\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/components/downloads/SubtitleWorkshop.svelte","lineNumber":259,"sourceCode":"    const b = na - a * oa;\n    cues = cues.map((c) => ({\n      ...c,\n      start_ms: Math.max(0, Math.round(a * c.start_ms + b)),\n      end_ms: Math.max(0, Math.round(a * c.end_ms + b)),\n    }));\n  }\n\n  async function saveAs(format: \"srt\" | \"vtt\" | \"ass\") {\n    if (!cues.length) return;\n    const path = await saveDialog({\n      filters: [{ name: format.toUpperCase(), extensions: [format] }],\n    });\n    if (!path) return;\n    try {\n      await invoke(\"subtitle_save\", { path, cues, format });\n      showToast(\"success\", $t(\"downloads.sw.saved\") as string);\n    } catch (e) {\n      err(e);\n    }\n  }\n</script>\n\n<div\n  class=\"overlay\"\n  role=\"button\"\n  tabindex=\"0\"\n  onclick={(e) => { if (e.target === e.currentTarget) onClose(); }}\n  onkeydown={(e) => { if (e.key === \"Escape\") onClose(); }}\n>\n  <div class=\"panel\" role=\"dialog\" aria-modal=\"true\" aria-label={$t('downloads.sw.title') as string}>\n    <div class=\"head\">\n      <h2>{$t('downloads.sw.title')}</h2>\n      <button class=\"x\" onclick={onClose} aria-label={$t('common.close') as string}>✕</button>\n    </div>\n\n    <div class=\"toolbar\">","sourceCodeStart":241,"sourceCodeEnd":277,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src/components/downloads/SubtitleWorkshop.svelte#L241-L277","documentation":"The Tauri backend command `subtitle_save` failed while persisting subtitle cues to the path chosen via saveAs. The component intentionally rethrows the backend error to the user via the shared err() helper, which shows a localized toast instead of a success message.","triggerScenarios":"invoke(\"subtitle_save\", { path, cues, format }) rejects: unwritable/invalid path, unsupported format string, backend serialization failure on cues, or filesystem permission errors on save.","commonSituations":"Saving to a read-only or cloud-synced directory, invalid characters in filename, backend command renamed/changed signature after an app update, or cues containing data the serializer cannot encode.","solutions":["Check the toast/backend message for the concrete cause (path vs format vs serialization)","Verify the target directory is writable and the path is valid for the OS","Confirm the format value matches a backend-supported subtitle format","Retry the save with a different location/filename"],"exampleFix":"// before\ncatch (e) {\n  err(e);\n}\n// after\ncatch (e) {\n  err(e);\n  showToast(\"error\", $t(\"downloads.sw.save_failed_hint\") as string);\n  console.warn(\"subtitle_save failed\", e);\n}","handlingStrategy":"try-catch","validationCode":"if (!path || typeof path !== \"string\" || path.trim() === \"\") return;\nif (!cues?.length) return;","typeGuard":"function isValidPath(p: unknown): p is string {\n  return typeof p === \"string\" && p.trim().length > 0;\n}","tryCatchPattern":"try {\n  await invoke(\"subtitle_save\", { path, cues, format });\n  showToast(\"success\", $t(\"downloads.sw.saved\") as string);\n} catch (e) {\n  const msg = typeof e === \"string\" ? e : (e as Error)?.message ?? String(e);\n  err(msg);\n  showToast(\"error\", $t(\"downloads.sw.save_failed\") as string);\n}","preventionTips":["Validate the save path and cues before invoking","Restrict format to backend-supported values","Prefer user-chosen paths from the OS save dialog over constructed paths","Handle save-failure UX distinctly from success"],"tags":["tauri","filesystem","subtitle-export"],"backgroundTag":"file-write-failed","analyzedSha":"8600b91f4246848bac346874daa9e61c1fc5677a","analyzedAt":"2026-09-12T14:29:19.317Z","contentChangedAt":"2026-09-12T14:29:19.317Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}