siyuan-note/siyuan · error

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

Error message

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

What it means

formatNotebookWriteError maps model.ErrBoxClosed (returned by notebook write operations on a closed notebook) into an actionable message telling the user the notebook is closed and to run `notebook open --id <id>` first. SiYuan requires notebooks to be open (mounted/indexed) before documents can be written into them.

Solutions

  1. Run `siyuan notebook open --id <boxID>` to open the notebook, then retry the operation.
  2. List open notebooks first to check state before performing write commands.
  3. In scripts, open the notebook as a pre-step before any write operations.

Example fix

// before
siyuan notebook rename --id 20240101120000-abcd123 --name "New"  // closed
// after
siyuan notebook open --id 20240101120000-abcd123
siyuan notebook rename --id 20240101120000-abcd123 --name "New"
Defensive patterns

Strategy: try-catch

Validate before calling

# check the notebook is open before writing
open_ids=$(curl -s http://127.0.0.1:6806/api/notebook/lsNotebooks | jq -r '.data.notebooks[].id')
echo "$open_ids" | grep -q "$BOX_ID" || siyuan notebook open --id "$BOX_ID"

Try / catch

if ! siyuan notebook rename --id "$BOX_ID" --name "$NAME"; then
  siyuan notebook open --id "$BOX_ID"
  siyuan notebook rename --id "$BOX_ID" --name "$NAME"
fi

Prevention

When it happens

Trigger: Any notebook write command (e.g. notebook rename/remove flows wrapping model calls) where the underlying model call returns model.ErrBoxClosed because the target notebook was closed via `notebook close` or was never opened.

Common situations: Scripting against a notebook that was closed earlier in the session; a fresh workspace where the notebook is present on disk but not yet opened; renaming a notebook that the UI has closed.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/96104b4df6b29b3b. Report an issue: GitHub.

Appendix: 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 9f775e8a12)