cjpais/Handy · warning

Failed to sync theme from settings:

Error message

Failed to sync theme from settings:

What it means

syncThemeFromSettings calls getAppSettings and applies result.data.theme ('light' | 'dark' | 'system') to the document. The ok-status path is handled and the error-status path is silently ignored; this catch only sees a rejected invoke (backend unreachable, command unregistered, store plugin not ready, browser context). The visible symptom is the app keeping the default/system appearance instead of the user's persisted choice.

Source

Thrown at src/lib/utils/theme.ts:61

export const getStoredTheme = (): Theme => {
  try {
    const stored = localStorage.getItem(THEME_STORAGE_KEY);
    if (isTheme(stored)) return stored;
  } catch {
    // ignore
  }
  return "system";
};

/** Apply the persisted theme from AppSettings (the source of truth). */
export const syncThemeFromSettings = async (): Promise<void> => {
  try {
    const result = await commands.getAppSettings();
    if (result.status === "ok") {
      applyTheme(result.data.theme ?? "system");
    }
  } catch (e) {
    console.warn("Failed to sync theme from settings:", e);
  }
};

View on GitHub (pinned to c89b7bf389)

Solutions

  1. Call syncThemeFromSettings after the app/window ready event or once onboarding completes, not only at module import
  2. Verify the store plugin registration and capabilities include the settings command
  3. Guard browser dev with isTauri()
  4. Also handle result.status === "error" explicitly — an err status currently falls through with no log at all, which is the silent cousin of this warning

Example fix

// before
const result = await commands.getAppSettings();
if (result.status === "ok") {
  applyTheme(result.data.theme ?? "system");
}

// after
const result = await commands.getAppSettings();
if (result.status === "ok") {
  applyTheme(result.data.theme ?? "system");
} else if (result.status === "error") {
  console.warn("getAppSettings returned error, keeping default theme:", result.error);
}
Defensive patterns

Strategy: retry

Validate before calling

import { isTauri } from "@tauri-apps/api/core";
if (!isTauri()) return;

Try / catch

try {
  const result = await commands.getAppSettings();
  if (result.status === "ok") applyTheme(result.data.theme ?? "system");
  else console.warn("getAppSettings error status:", result.error);
} catch (e) { console.warn("Failed to sync theme from settings:", e); }

Prevention

When it happens

Trigger: Calling syncThemeFromSettings before the Tauri backend/store plugin is ready; the getAppSettings command not registered; running the frontend in a plain browser where invoke rejects; a settings-store file that fails to parse so the command rejects rather than returning an error status.

Common situations: Startup ordering issues when the module runs at import time; plugin/capability misconfigurations; dev iteration in Vite; migrated or corrupted settings files after schema changes.

Related errors


AI-assisted analysis of cjpais/Handy@c89b7bf389 (2026-08-17). Data as JSON: /api/errors/5922f5b20303e555. Report an issue: GitHub.