tonhowtf/omniget · error

create notebook failed

Error message

create notebook failed

What it means

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.

Solutions

  1. Read the logged error to distinguish validation rejection from IPC/DB failure.
  2. Validate the name (non-empty, length/charset limits) in the UI before calling create().
  3. Confirm 'study:notes:notebooks:create' is registered and allowed in capabilities.
  4. Handle the null return at call sites so the user gets feedback instead of a silent no-op.
  5. If the error came from refresh(), re-run refresh() — the notebook may already exist.

Example fix

// before
const id = await notebooksStore.create({ name: nameInput.trim() });
if (id === null) return; // silent failure
// after
const name = nameInput.trim();
if (!name) { showError("Notebook name is required"); return; }
const id = await notebooksStore.create({ name });
if (id === null) showError("Could not create notebook — check the console for details");
Defensive patterns

Strategy: validation

Validate before calling

function validateNotebookName(name: string): string | null {
  const n = name.trim();
  if (!n) return 'Name is required';
  if (n.length > 100) return 'Name too long (max 100 chars)';
  return null;
}
const err = validateNotebookName(input);
if (err) { showError(err); return; }

Type guard

function isCreatedId(r: { notebook_id: number } | null): r is { notebook_id: number } {
  return r !== null && typeof r.notebook_id === 'number';
}

Try / catch

const id = await notebooksStore.create({ name: trimmedName });
if (id === null) {
  showError('Notebook creation failed — see console for details');
  return;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

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/7211f41ec34be763. Report an issue: GitHub.

Appendix: source

Thrown at src/lib/study-notes/notebooks-store.svelte.ts:110

    this.activeId = notebookId;
    try {
      await notesNotebooksActiveSet(notebookId);
    } catch (e) {
      console.warn("setActive failed", e);
    }
  }

  async create(args: {
    name: string;
    color?: string | null;
    iconLucide?: string | null;
  }): Promise<number | null> {
    try {
      const r = await notesNotebooksCreate(args);
      await this.refresh();
      return r.notebook_id;
    } catch (e) {
      console.warn("create notebook failed", e);
      return null;
    }
  }

  async rename(notebookId: number, newName: string) {
    try {
      await notesNotebooksRename({ notebookId, newName });
      await this.refresh();
    } catch (e) {
      console.warn("rename failed", e);
    }
  }

  async close(notebookId: number) {
    try {
      await notesNotebooksClose(notebookId);
      if (this.activeId === notebookId) {
        await this.setActive(1);

View on GitHub (pinned to 8600b91f42)