siyuan-note/siyuan · error

notebook [%s] is closed; run `notebook open --id %s` first

Error message

notebook [%s] is closed; run `notebook open --id %s` first

What it means

Produced by `formatNotebookWriteError` when a notebook write operation returned `model.ErrBoxClosed`. The helper wraps the sentinel into an actionable message telling the caller to open the notebook first. It is returned by notebook write subcommands (rename, configure, document operations) whose target box is currently closed (unmounted).

Source

Thrown at kernel/cli/cmd/notebook.go:92

			return nil
		}

		id, err := model.CreateBox(name)
		if err != nil {
			return err
		}
		if _, err = model.Mount(id); err != nil {
			return fmt.Errorf("notebook [%s] was created but could not be opened: %w", id, err)
		}
		model.AppendPushReloadFiletreeEntry()
		fmt.Println(id)
		return nil
	},
}

func formatNotebookWriteError(boxID string, err error) error {
	if errors.Is(err, model.ErrBoxClosed) {
		return fmt.Errorf("notebook [%s] is closed; run `notebook open --id %s` first", boxID, boxID)
	}
	if errors.Is(err, model.ErrBoxNotFound) {
		return fmt.Errorf("notebook [%s] not found", boxID)
	}
	return err
}

var notebookRemoveCmd = &cobra.Command{
	Use:   "remove --id <id>",
	Short: "Remove a notebook",
	RunE: func(cmd *cobra.Command, args []string) error {
		id, _ := cmd.Flags().GetString("id")
		if id == "" {
			return fmt.Errorf("--id is required")
		}

		if dryRun {
			fmt.Printf("[dry-run] Would remove notebook %s\n", id)

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Open the notebook first: `siyuan notebook open --id <id>`, then retry the write
  2. Confirm the notebook is open with `siyuan notebook list` before scripting writes
  3. If open reports the box not found, the ID is wrong or the box was removed

Example fix

// before
siyuan notebook rename --id 20240101-xyz --name New
# -> error: notebook [20240101-xyz] is closed; run `notebook open --id 20240101-xyz` first
// after
siyuan notebook open --id 20240101-xyz && siyuan notebook rename --id 20240101-xyz --name New
Defensive patterns

Strategy: validation

Validate before calling

// Guard notebook writes by checking mount state first:
boxes, _ := model.ListNotebooks()
opened := false
for _, b := range boxes {
    if b.ID == boxID && b.Opened { opened = true; break }
}
if !opened {
    if _, err := model.Mount(boxID); err != nil { return err }
}

Try / catch

// Match the sentinel before surfacing a generic error:
if errors.Is(err, model.ErrBoxClosed) {
    // auto-open then retry, or instruct the user
    if _, mErr := model.Mount(boxID); mErr == nil { /* retry op */ }
}

Prevention

When it happens

Trigger: Calling a notebook write command against an ID whose box is closed — e.g. after `notebook close`, after a restart that did not auto-mount, or on a box the user manually closed in the GUI. `formatNotebookWriteError` matches the error with `errors.Is(err, model.ErrBoxClosed)` and formats the remediation hint.

Common situations: Notebooks are closed by default after certain operations or manually via the GUI; scripts that assume all notebooks are open; operating on a freshly created notebook whose mount failed (see error 238).

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/96104b4df6b29b3b. Report an issue: GitHub.