{"record":{"id":"ff3e659100b079ce","repo":"tonhowtf/omniget","slug":"notebooksstore-refresh-failed","errorCode":null,"errorMessage":"notebooksStore.refresh failed","messagePattern":"notebooksStore\\.refresh failed","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/lib/study-notes/notebooks-store.svelte.ts","lineNumber":78,"sourceCode":"      const [rows, active] = await Promise.all([\n        notesNotebooksList({ includeClosed: true }),\n        notesNotebooksActiveGet(),\n      ]);\n      this.list = rows;\n      this.activeId = active.notebook_id;\n    } catch (e) {\n      console.warn(\"notebooksStore.hydrate failed\", e);\n    } finally {\n      this.hydrated = true;\n      this.loading = false;\n    }\n  }\n\n  async refresh() {\n    try {\n      this.list = await notesNotebooksList({ includeClosed: true });\n    } catch (e) {\n      console.warn(\"notebooksStore.refresh failed\", e);\n    }\n  }\n\n  pageCountOf(id: number): number {\n    return this.list.find((n) => n.id === id)?.page_count ?? 0;\n  }\n\n  byId(id: number): Notebook | null {\n    return this.list.find((n) => n.id === id) ?? null;\n  }\n\n  async setActive(notebookId: number) {\n    if (this.activeId === notebookId) return;\n    this.activeId = notebookId;\n    try {\n      await notesNotebooksActiveSet(notebookId);\n    } catch (e) {\n      console.warn(\"setActive failed\", e);","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src/lib/study-notes/notebooks-store.svelte.ts#L60-L96","documentation":"notebooksStore.refresh() reloads the notebook list via notesNotebooksList({includeClosed:true}), a Tauri pluginInvoke of 'study:notes:notebooks:list'. On rejection the catch logs 'notebooksStore.refresh failed' and leaves this.list stale. All mutating store actions (create, rename, close, reopen, delete, movePage) call refresh afterwards, so a failed refresh shows outdated notebook state even when the mutation itself succeeded.","triggerScenarios":"notesNotebooksList rejects: backend command error, notes DB unavailable, plugin/capability misconfiguration, or IPC failure; it runs after every successful mutation, so it also fires when only the follow-up list query fails.","commonSituations":"Backend list endpoint broken after a schema migration; DB locked by another writer; command renamed on the backend but not the bridge; running outside the Tauri shell so pluginInvoke rejects; transient IPC failure right after a mutation.","solutions":["Inspect the logged rejection reason from notesNotebooksList to identify the backend error.","Verify 'study:notes:notebooks:list' exists and is allowed in Tauri capabilities.","Test the bridge call directly from the console to isolate store vs backend.","If the DB is locked or corrupted, resolve the writer contention or repair the notes DB.","Make UI affordances call refresh() again (retry) since the swallowed error leaves this.list stale."],"exampleFix":"// before\nasync refresh() {\n  try {\n    this.list = await notesNotebooksList({ includeClosed: true });\n  } catch (e) {\n    console.warn(\"notebooksStore.refresh failed\", e);\n  }\n}\n// after\nasync refresh() {\n  try {\n    this.list = await notesNotebooksList({ includeClosed: true });\n  } catch (e) {\n    console.warn(\"notebooksStore.refresh failed\", e);\n    this.refreshFailed = true; // surface staleness to the UI for retry\n  }\n}","handlingStrategy":"retry","validationCode":"// guard before treating list as authoritative\nif (!notebooksStore.hydrated) await notebooksStore.hydrate();\nconst count = notebooksStore.list.length;","typeGuard":"function hasErrorReason(e: unknown): e is Error {\n  return e instanceof Error;\n}","tryCatchPattern":"let lastErr: unknown;\nfor (let i = 0; i < 3; i++) {\n  await notebooksStore.refresh();\n  if (notebooksStore.list.length > 0) break;\n  lastErr = new Error('refresh returned empty');\n  await new Promise((r) => setTimeout(r, 300 * (i + 1)));\n}","preventionTips":["Re-call refresh() after any mutation failure to resync UI state","Track a refreshFailed/staleAt timestamp so the UI can show staleness","Keep bridge command names in sync with backend command registry","Add retries with backoff for list-type reads","Monitor console warnings in dev builds to catch backend regressions early"],"tags":["svelte","tauri","ipc","stale-state","error-handling"],"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-15T23:17:13.987Z"}