{"record":{"id":"bc156e94dee64825","repo":"tonhowtf/omniget","slug":"player-failed-saving-auto-skip-on-error","errorCode":null,"errorMessage":"[player] failed saving auto_skip_on_error","messagePattern":"\\[player\\] failed saving auto_skip_on_error","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/lib/study-music/player-store.svelte.ts","lineNumber":522,"sourceCode":"    this.playerSettingsLoaded = true;\n    try {\n      const res = await pluginInvoke<{\n        auto_skip_on_error?: boolean;\n      }>(\"study\", \"study:music:player:settings:get\", {});\n      this.autoSkipOnError = !!res?.auto_skip_on_error;\n    } catch (e) {\n      console.warn(\"[player] failed loading player settings\", e);\n    }\n  }\n\n  async setAutoSkipOnError(value: boolean) {\n    this.autoSkipOnError = value;\n    try {\n      await pluginInvoke(\"study\", \"study:music:player:settings:set\", {\n        auto_skip_on_error: value,\n      });\n    } catch (e) {\n      console.warn(\"[player] failed saving auto_skip_on_error\", e);\n    }\n  }\n\n  private setError(err: PlayerError) {\n    this.lastError = err;\n    this.error = err.message || null;\n    this.status = \"error\";\n    this.loading = false;\n    if (this.autoSkipOnError && !err.retriable) {\n      const skipDelay = 300;\n      setTimeout(() => {\n        if (this.lastError && this.lastError.trackId === err.trackId) {\n          this.skipOnError();\n        }\n      }, skipDelay);\n    }\n  }\n","sourceCodeStart":504,"sourceCodeEnd":540,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src/lib/study-music/player-store.svelte.ts#L504-L540","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","Inspect the logged error object `e` to distinguish missing-command vs IPC/permission failures.","Verify the payload key auto_skip_on_error is a plain boolean (serialization mismatches cause backend rejections).","Queue a retry or re-sync settings on app start so the preference is eventually persisted."],"exampleFix":"// before\nawait pluginInvoke(\"study\", \"study:music:player:settings:set\", { auto_skip_on_error: value });\n// after\nawait pluginInvoke(\"study\", \"study:music:player:settings:set\", { auto_skip_on_error: Boolean(value) }); // plus ensure command exists and capability allows study:player:settings","handlingStrategy":"try-catch","validationCode":"// ensure backend command exists before saving\nconst supported = await pluginInvoke<boolean>(\"study\", \"study:music:player:settings:has\").catch(() => false);","typeGuard":"function isSettingsPayload(v: unknown): v is { auto_skip_on_error: boolean } {\n  return typeof v === \"object\" && v !== null && typeof (v as any).auto_skip_on_error === \"boolean\";\n}","tryCatchPattern":"try {\n  await pluginInvoke(\"study\", \"study:music:player:settings:set\", { auto_skip_on_error: Boolean(value) });\n} catch (e) {\n  console.warn(\"[player] failed saving auto_skip_on_error\", e);\n  this.pendingSettingSync = true; // retry on next app start\n}","preventionTips":["Keep frontend command names in sync with backend registrations via a shared constants module.","Add Tauri capability/permission entries whenever adding plugin commands.","Re-sync settings from backend on startup to detect unpersisted values.","Serialize booleans explicitly (Boolean(value)) before IPC."],"tags":["tauri","ipc","settings-persistence","music-player"],"backgroundTag":"api-request-failed","analyzedSha":"8600b91f4246848bac346874daa9e61c1fc5677a","analyzedAt":"2026-09-12T14:29:19.317Z","contentChangedAt":"2026-09-12T14:29:19.317Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}