siyuan-note/siyuan · warning

kernel is exiting

Error message

kernel is exiting

What it means

writeRenameDoc performs the document rename write while holding the hpath refresh lock. Before writing it checks util.IsExiting; if the kernel is shutting down it aborts with this error so a rename is never half-applied during shutdown, which could leave document paths and the hpath refresh queue inconsistent.

Solutions

  1. Retry the rename after the kernel restarts
  2. Ensure the kernel is fully stopped before issuing further API calls in shutdown/automation scripts
  3. Add a shutdown hook or ordering so renames are drained before the exit flag is set
  4. Handle the returned error in the caller and surface 'kernel is shutting down' to the user instead of a generic failure
Defensive patterns

Strategy: retry

Try / catch

n, err := model.RenameDoc(box, path, title); if err != nil && err.Error() == "kernel is exiting" { // wait for restart, then retry the rename }

Prevention

When it happens

Trigger: Invoking a document rename API (which reaches renameWriteJSONQueue -> writeRenameDoc) while the kernel is shutting down (util.IsExiting set), e.g. a rename request racing the quit sequence.

Common situations: Scripts or automation issuing rename calls right as the user closes the app; long-running API requests delayed until after shutdown started; CI/scripts that kill the kernel while requests are in flight.

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

Appendix: source

Thrown at kernel/model/hpath_refresh.go:260

	if err = saveHPathRefreshLocked(); err != nil {
		if previous == nil {
			delete(hpathRefresh.tasks, key)
		} else {
			hpathRefresh.tasks[key] = previous
		}
	}
	return
}

func writeRenameDoc(tree *parse.Tree) (size uint64, err error) {
	if err = AcquireEncryptedBoxOperation(tree.Box); err != nil {
		return
	}
	defer ReleaseEncryptedBoxOperation(tree.Box)
	hpathRefresh.Lock()
	defer hpathRefresh.Unlock()
	if util.IsExiting.Load() {
		return 0, errors.New("kernel is exiting")
	}
	tree.HPath = treenode.CurrentParentHPath(tree)
	key, err := queueHPathRefreshLocked(tree)
	if err != nil {
		return 0, err
	}
	if size, err = filesys.WriteTree(tree); err != nil {
		return
	}
	if treenode.GetBlockTreeInBox(tree.ID, tree.Box) == nil {
		treenode.UpsertBlockTree(tree)
	}
	if err = treenode.RefreshDocHPaths(tree); err != nil {
		return
	}
	sql.RenameDocQueue(tree)
	hpathRefresh.tasks[key].recover = false
	return

View on GitHub (pinned to 9f775e8a12)