{"record":{"id":"684b824ce08cdb93","repo":"tonhowtf/omniget","slug":"subtitle-translate-error-surfaced-to-user-via-err-localized","errorCode":null,"errorMessage":"subtitle_translate error surfaced to user via err() (localized toast)","messagePattern":"subtitle_translate error surfaced to user via err\\(\\) \\(localized toast\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/components/downloads/SubtitleWorkshop.svelte","lineNumber":163,"sourceCode":"    if (i < cues.length - 1 && cues[i + 1].start_ms < c.end_ms)\n      return $t(\"downloads.sw.qc_overlap\") as string;\n    const secs = (c.end_ms - c.start_ms) / 1000;\n    const cps = secs > 0 ? c.text.replace(/\\s/g, \"\").length / secs : 99;\n    if (cps > 21) return $t(\"downloads.sw.qc_fast\") as string;\n    return null;\n  }\n\n  async function translateAll() {\n    if (!targetLang.trim() || !cues.length || busy) return;\n    busy = true;\n    try {\n      cues = await invoke<Cue[]>(\"subtitle_translate\", {\n        cues,\n        targetLang: targetLang.trim(),\n      });\n      showToast(\"success\", $t(\"downloads.sw.translated\") as string);\n    } catch (e) {\n      err(e);\n    } finally {\n      busy = false;\n    }\n  }\n\n  async function grammarFix() {\n    if (!cues.length || busy) return;\n    busy = true;\n    try {\n      cues = await invoke<Cue[]>(\"subtitle_grammar_fix\", {\n        cues,\n        style: grammarStyle,\n      });\n      showToast(\"success\", $t(\"downloads.sw.grammar_done\") as string);\n    } catch (e) {\n      err(e);\n    } finally {\n      busy = false;","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src/components/downloads/SubtitleWorkshop.svelte#L145-L181","documentation":"translateAll failed while invoking subtitle_translate to machine-translate all cues to the target language; err() surfaces the backend error as a localized toast and cues are left unchanged. A raw 'ai_not_configured' code from the backend is specifically mapped to a 'not configured' message.","triggerScenarios":"invoke('subtitle_translate',{cues,targetLang}) rejecting — AI/translation backend not configured (ai_not_configured), empty/invalid targetLang, API failure upstream (rate limit, key invalid), or cues payload rejected.","commonSituations":"No AI provider/API key configured on the backend; empty or malformed target language string; translation service outage or quota exhaustion; extremely large subtitle files exceeding request limits.","solutions":["If the toast shows the not-configured message, configure the AI/translation provider and key in backend settings.","Validate targetLang is a non-empty supported language code before invoking.","Check upstream API status/limits if the error mentions request failure or rate limiting.","Retry smaller batches of cues if payload size is the issue."],"exampleFix":"// before\nawait invoke(\"subtitle_translate\", { cues, targetLang: targetLang.trim() });\n// after\nconst lang = targetLang.trim();\nif (!lang) { showToast(\"error\", $t(\"downloads.sw.enter_language\")); return; }\nawait invoke(\"subtitle_translate\", { cues, targetLang: lang });","handlingStrategy":"validation","validationCode":"const lang = targetLang.trim();\nif (!lang) { showToast(\"error\", $t(\"downloads.sw.enter_language\")); return; }\nif (!(await invoke<boolean>(\"ai_configured\").catch(() => false))) { err(\"ai_not_configured\"); return; }","typeGuard":"function isValidTargetLang(v: unknown): v is string {\n  return typeof v === \"string\" && /^[a-z]{2}(-[A-Z]{2})?$/.test(v.trim());\n}","tryCatchPattern":"try {\n  cues = await invoke<Cue[]>(\"subtitle_translate\", { cues, targetLang: lang });\n  showToast(\"success\", $t(\"downloads.sw.translated\") as string);\n} catch (e) {\n  err(e); // localized toast; maps ai_not_configured etc.\n} finally {\n  busy = false;\n}","preventionTips":["Configure the AI/translation provider and key before exposing translate in the UI.","Validate the target language code client-side before invoking.","Check AI provider quota/limits and back off on rate-limit errors.","Chunk very large cue lists to avoid oversized requests."],"tags":["tauri","invoke","translation","ai"],"backgroundTag":"missing-api-key","analyzedSha":"8600b91f4246848bac346874daa9e61c1fc5677a","analyzedAt":"2026-09-12T14:29:19.317Z","contentChangedAt":"2026-09-12T14:29:19.317Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}