tonhowtf/omniget · warning

[player] failed saving auto_skip_on_error

Error message

[player] failed saving auto_skip_on_error

What it means

MusicPlayerStore logs this warning when persisting the auto_skip_on_error playback setting to the Tauri 'study' plugin backend via study:music:player:settings:set fails. The in-memory value (autoSkipOnError) is still applied, so playback behaves as requested for the session, but the preference is not saved. It is a non-fatal durability failure, not a playback failure.

Solutions

  1. Check the backend exposes the study:music:player:settings:set command and that the 'study' plugin is registered and allowed in the Tauri capability/allowlist config.
  2. Inspect the logged error object `e` to distinguish missing-command vs IPC/permission failures.
  3. Verify the payload key auto_skip_on_error is a plain boolean (serialization mismatches cause backend rejections).
  4. Queue a retry or re-sync settings on app start so the preference is eventually persisted.

Example fix

// before
await pluginInvoke("study", "study:music:player:settings:set", { auto_skip_on_error: value });
// after
await pluginInvoke("study", "study:music:player:settings:set", { auto_skip_on_error: Boolean(value) }); // plus ensure command exists and capability allows study:player:settings
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure backend command exists before saving
const supported = await pluginInvoke<boolean>("study", "study:music:player:settings:has").catch(() => false);

Type guard

function isSettingsPayload(v: unknown): v is { auto_skip_on_error: boolean } {
  return typeof v === "object" && v !== null && typeof (v as any).auto_skip_on_error === "boolean";
}

Try / catch

try {
  await pluginInvoke("study", "study:music:player:settings:set", { auto_skip_on_error: Boolean(value) });
} catch (e) {
  console.warn("[player] failed saving auto_skip_on_error", e);
  this.pendingSettingSync = true; // retry on next app start
}

Prevention

When it happens

Trigger: Calling the store's auto-skip-on-error setter with a boolean and the pluginInvoke('study','study:music:player:settings:set',{auto_skip_on_error:value}) call rejecting — backend command missing, plugin not registered, IPC failure, or backend rejecting the payload.

Common situations: Running the frontend against a backend build without the settings:set command; Tauri plugin permission for the 'study' plugin not granted; backend restarting or connection dropped mid-call; typo'd/renamed command after a refactor.

Understand the failure class

Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.

Related errors


AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12). Data as JSON: /api/errors/bc156e94dee64825. Report an issue: GitHub.

Appendix: source

Thrown at src/lib/study-music/player-store.svelte.ts:522

    this.playerSettingsLoaded = true;
    try {
      const res = await pluginInvoke<{
        auto_skip_on_error?: boolean;
      }>("study", "study:music:player:settings:get", {});
      this.autoSkipOnError = !!res?.auto_skip_on_error;
    } catch (e) {
      console.warn("[player] failed loading player settings", e);
    }
  }

  async setAutoSkipOnError(value: boolean) {
    this.autoSkipOnError = value;
    try {
      await pluginInvoke("study", "study:music:player:settings:set", {
        auto_skip_on_error: value,
      });
    } catch (e) {
      console.warn("[player] failed saving auto_skip_on_error", e);
    }
  }

  private setError(err: PlayerError) {
    this.lastError = err;
    this.error = err.message || null;
    this.status = "error";
    this.loading = false;
    if (this.autoSkipOnError && !err.retriable) {
      const skipDelay = 300;
      setTimeout(() => {
        if (this.lastError && this.lastError.trackId === err.trackId) {
          this.skipOnError();
        }
      }, skipDelay);
    }
  }

View on GitHub (pinned to 8600b91f42)