tonhowtf/omniget · warning
$t('common.error') | mapped: ai_not_configured -> $t('downlo
Error message
$t('common.error') | mapped: ai_not_configured -> $t('downloads.sw.not_configured'), translation_mismatch -> $t('downloads.sw.translate_mismatch'), grammar_mismatch -> $t('downloads.sw.grammar_mismatch') What it means
SubtitleWorkshop's err() is the shared error-mapper used by all invoke call-sites in the component. It takes the raw error (usually a string error code from the Rust backend), falls back to the localized common.error label when the error isn't a string, and maps known codes like ai_not_configured, translation_mismatch and grammar_mismatch to user-facing localized messages. The 'error message' here is that mapping contract, not a throw itself.
Solutions
- Extend err()'s mapping table whenever the backend adds a new error code string.
- Ensure invoke rejections are plain strings (backend should return string error codes, not throw Error objects).
- Verify downloads.sw.* and common.error keys exist in every locale bundle.
- Log the unmapped raw error to console so unknown codes can be discovered and mapped.
Example fix
// before
const raw = typeof e === "string" ? e : ($t("common.error") as string);
// after
const raw = typeof e === "string" ? e : ((e as Error)?.message ?? ($t("common.error") as string));
console.warn("unmapped subtitle workshop error:", e); Defensive patterns
Strategy: type-guard
Validate before calling
const KNOWN_CODES = ["ai_not_configured", "translation_mismatch", "grammar_mismatch"] as const; // keep backend error-code list exported from a shared module and diff it against KNOWN_CODES in a test
Type guard
function isBackendErrorCode(v: unknown): v is string {
return typeof v === "string" && v.length > 0 && !v.includes(" ");
} Try / catch
function err(e: unknown) {
const raw = typeof e === "string"
? e
: ((e as Error)?.message ?? ($t("common.error") as string));
if (!KNOWN_CODES.includes(raw as any)) console.warn("unmapped error code:", raw);
showToast("error", mapCodeToMessage(raw));
} Prevention
- Maintain a single shared source of truth for backend error codes and test the mapper against it.
- Always reject with plain string codes from Rust commands consumed by this component.
- Add fallback text for every new sw.* i18n key in all locales.
- Log unmapped codes so gaps in the mapping table surface in development.
When it happens
Trigger: err(e) is invoked from loadFile, loadMedia, translateAll, grammarFix or saveAs when a Tauri invoke rejects with a raw code string; if the code is 'ai_not_configured', 'translation_mismatch' or 'grammar_mismatch' it is translated, any non-string error falls back to the generic $t('common.error') text.
Common situations: Backend adds a new error code that err() doesn't map, so users see a generic message; an invoke rejects with an Error object instead of a string, losing the specific reason; translations for the sw.* keys missing from a locale file show raw keys.
Related errors
- subtitle_load error surfaced to user via err() (localized to
- waveform_peaks/detect_shot_changes error surfaced to user vi
- subtitle_translate error surfaced to user via err() (localiz
- subtitle_grammar_fix error surfaced to user via err() (local
- escolha a pasta de destino para organizar
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/508769ed07db2fb1.
Report an issue: GitHub.
Appendix: source
Thrown at src/components/downloads/SubtitleWorkshop.svelte:27
type Cue = { start_ms: number; end_ms: number; text: string };
let cues = $state<Cue[]>([]);
let loadedPath = $state("");
let busy = $state(false);
let shiftMs = $state(0);
let findText = $state("");
let replaceText = $state("");
let targetLang = $state("");
let grammarStyle = $state<"original" | "formal" | "casual">("original");
let tpOldA = $state("");
let tpNewA = $state("");
let tpOldB = $state("");
let tpNewB = $state("");
let peaks = $state<number[]>([]);
let shots = $state<number[]>([]);
let durationMs = $derived(cues.length ? cues[cues.length - 1].end_ms : 0);
function err(e: unknown) {
const raw = typeof e === "string" ? e : ($t("common.error") as string);
const msg =
raw === "ai_not_configured"
? ($t("downloads.sw.not_configured") as string)
: raw === "translation_mismatch"
? ($t("downloads.sw.translate_mismatch") as string)
: raw === "grammar_mismatch"
? ($t("downloads.sw.grammar_mismatch") as string)
: raw;
showToast("error", msg);
}
function fmt(ms: number): string {
const s = Math.floor(ms / 1000);
const h = Math.floor(s / 3600);
const m = Math.floor((s % 3600) / 60);
const sec = s % 60;
const milli = ms % 1000;View on GitHub (pinned to 8600b91f42)