{"record":{"id":"cbe66b392e55d2e1","repo":"cjpais/Handy","slug":"failed-to-sync-language-from-settings","errorCode":null,"errorMessage":"Failed to sync language from settings:","messagePattern":"Failed to sync language from settings:","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/i18n/index.ts","lineNumber":120,"sourceCode":"// Sync language from app settings\nexport const syncLanguageFromSettings = async () => {\n  try {\n    const result = await commands.getAppSettings();\n    if (result.status === \"ok\" && result.data.app_language) {\n      const supported = getSupportedLanguage(result.data.app_language);\n      if (supported && supported !== i18n.language) {\n        await i18n.changeLanguage(supported);\n      }\n    } else {\n      // Fall back to system locale detection if no saved preference\n      const systemLocale = await locale();\n      const supported = getSupportedLanguage(systemLocale);\n      if (supported && supported !== i18n.language) {\n        await i18n.changeLanguage(supported);\n      }\n    }\n  } catch (e) {\n    console.warn(\"Failed to sync language from settings:\", e);\n  }\n};\n\n// Run language sync on init\nsyncLanguageFromSettings();\n\n// Listen for language changes to update HTML dir and lang attributes\ni18n.on(\"languageChanged\", (lng) => {\n  const dir = getLanguageDirection(lng);\n  updateDocumentDirection(dir);\n  updateDocumentLanguage(lng);\n});\n\n// Re-export RTL utilities for convenience\nexport { getLanguageDirection, isRTLLanguage } from \"@/lib/utils/rtl\";\n\nexport default i18n;\n","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/cjpais/Handy/blob/c89b7bf38974ad317177389f5bfe28236f0d64e3/src/i18n/index.ts#L102-L138","documentation":"syncLanguageFromSettings reads the persisted AppSettings via the getAppSettings Tauri command; if no app_language is saved it falls back to the OS locale from @tauri-apps/plugin-os, then calls i18n.changeLanguage on the resolved supported code. Any rejection anywhere in that chain (store read, OS plugin, changeLanguage) lands in this catch and is logged; the app silently keeps i18next's default 'en'. Note it runs at module load time (line 125), which makes backend-not-ready races the dominant cause.","triggerScenarios":"Module evaluated before the Tauri backend/store plugin is initialized (it is called at import time, not after app ready); plugin-os not installed or missing from capabilities so locale() rejects; the settings store file unreadable/corrupted; frontend executed in a plain browser where every invoke rejects.","commonSituations":"Startup races on slower disks; capability (permissions) misconfiguration after upgrading Tauri; running the Vite dev server standalone; a first run where the store file does not exist yet and the command errors instead of returning defaults.","solutions":["Check the logged error object first: 'command not found' points to registration, a plugin permission error points to capabilities","Re-invoke syncLanguageFromSettings from App.tsx after onboarding/ready instead of relying solely on the module-load call","Ensure the store and os plugins are registered in Rust and listed in tauri.conf.json capabilities","Guard with isTauri() so browser-only development does not spam the warning"],"exampleFix":"// before (src/i18n/index.ts, module scope)\n// Run language sync on init\nsyncLanguageFromSettings();\n\n// after: keep module-scope call but add a ready-time retry in App.tsx\nuseEffect(() => {\n  if (onboardingStep === \"done\") void syncLanguageFromSettings();\n}, [onboardingStep]);","handlingStrategy":"retry","validationCode":"import { isTauri } from \"@tauri-apps/api/core\";\nif (!isTauri()) return; // avoid invoking outside the Tauri shell","typeGuard":null,"tryCatchPattern":"try { await syncLanguageFromSettings(); }\ncatch { /* sync itself swallows; re-run after ready */ }","preventionTips":["Do not rely on module-load-time sync alone — call syncLanguageFromSettings again after app ready/onboarding completes","Keep store and os plugins in capabilities when upgrading Tauri; invoke permission errors show up here","Log the error payload: 'command not found' vs permission vs parse errors have different fixes"],"tags":["tauri","i18n","settings","startup","invoke"],"backgroundTag":"tauri-command-invoke-failed","analyzedSha":"c89b7bf38974ad317177389f5bfe28236f0d64e3","analyzedAt":"2026-08-17T10:29:55.597Z","contentChangedAt":"2026-08-17T10:29:55.597Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}