{"record":{"id":"7211f41ec34be763","repo":"tonhowtf/omniget","slug":"create-notebook-failed","errorCode":null,"errorMessage":"create notebook failed","messagePattern":"create notebook failed","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/lib/study-notes/notebooks-store.svelte.ts","lineNumber":110,"sourceCode":"    this.activeId = notebookId;\n    try {\n      await notesNotebooksActiveSet(notebookId);\n    } catch (e) {\n      console.warn(\"setActive failed\", e);\n    }\n  }\n\n  async create(args: {\n    name: string;\n    color?: string | null;\n    iconLucide?: string | null;\n  }): Promise<number | null> {\n    try {\n      const r = await notesNotebooksCreate(args);\n      await this.refresh();\n      return r.notebook_id;\n    } catch (e) {\n      console.warn(\"create notebook failed\", e);\n      return null;\n    }\n  }\n\n  async rename(notebookId: number, newName: string) {\n    try {\n      await notesNotebooksRename({ notebookId, newName });\n      await this.refresh();\n    } catch (e) {\n      console.warn(\"rename failed\", e);\n    }\n  }\n\n  async close(notebookId: number) {\n    try {\n      await notesNotebooksClose(notebookId);\n      if (this.activeId === notebookId) {\n        await this.setActive(1);","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src/lib/study-notes/notebooks-store.svelte.ts#L92-L128","documentation":"notebooksStore.create() calls notesNotebooksCreate (Tauri command 'study:notes:notebooks:create') and then refresh(). If creation rejects, the catch logs 'create notebook failed' and the promise resolves to null, which callers must treat as 'no notebook created'. Backend validation (empty name, duplicates), DB write errors, or IPC failure all surface here.","triggerScenarios":"notesNotebooksCreate(args) rejects: backend rejects the name (empty/too long/invalid characters), the notes DB write fails, the plugin command is unavailable, or the Tauri IPC call fails; also fires if the subsequent refresh() throws, though the notebook was actually created in that case.","commonSituations":"User submits an empty or whitespace-only notebook name; name collides with backend uniqueness rules; DB locked or disk full; capability missing for the create command; running in a non-Tauri environment.","solutions":["Read the logged error to distinguish validation rejection from IPC/DB failure.","Validate the name (non-empty, length/charset limits) in the UI before calling create().","Confirm 'study:notes:notebooks:create' is registered and allowed in capabilities.","Handle the null return at call sites so the user gets feedback instead of a silent no-op.","If the error came from refresh(), re-run refresh() — the notebook may already exist."],"exampleFix":"// before\nconst id = await notebooksStore.create({ name: nameInput.trim() });\nif (id === null) return; // silent failure\n// after\nconst name = nameInput.trim();\nif (!name) { showError(\"Notebook name is required\"); return; }\nconst id = await notebooksStore.create({ name });\nif (id === null) showError(\"Could not create notebook — check the console for details\");","handlingStrategy":"validation","validationCode":"function validateNotebookName(name: string): string | null {\n  const n = name.trim();\n  if (!n) return 'Name is required';\n  if (n.length > 100) return 'Name too long (max 100 chars)';\n  return null;\n}\nconst err = validateNotebookName(input);\nif (err) { showError(err); return; }","typeGuard":"function isCreatedId(r: { notebook_id: number } | null): r is { notebook_id: number } {\n  return r !== null && typeof r.notebook_id === 'number';\n}","tryCatchPattern":"const id = await notebooksStore.create({ name: trimmedName });\nif (id === null) {\n  showError('Notebook creation failed — see console for details');\n  return;\n}","preventionTips":["Always trim and validate names before calling create()","Treat null return as failure and inform the user — it never throws","Check backend name uniqueness/length rules and mirror them client-side","If null but refresh shows the notebook, handle the refresh-race case","Test create against the real backend, not just the happy-path mock"],"tags":["svelte","tauri","ipc","validation","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"}