siyuan-note/siyuan · error

panic during siyuan.storage.remove

Error message

panic during siyuan.storage.remove: %v

What it means

The background goroutine executing os.RemoveAll for siyuan.storage.remove has a deferred recover(); if the removal pipeline panics, the panic is converted into this error and the plugin's Promise is rejected with it. It signals an unexpected internal crash, not a normal filesystem error (those surface as 'failed to remove').

Solutions

  1. Check the kernel log for the surrounding stack/panic message and report it with the plugin name
  2. Ensure the plugin is not being unloaded while storage operations are pending (await Promises before unload)
  3. Retry the removal once; transient runtime state issues may clear
  4. Update SiYuan kernel and the plugin to the latest versions
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await siyuan.storage.remove(path);
} catch (e) {
  if (String(e).includes("panic during")) {
    console.error("kernel-internal panic; report with kernel logs");
  } else throw e;
}

Prevention

When it happens

Trigger: A runtime panic inside the storage.remove goroutine while executing or while resolving/rejecting the Promise via the goja worker. Rare; typically indicates a bug in the runtime bridge rather than caller input.

Common situations: Kernel-internal panics in the JS-worker bridge; concurrently closing the plugin/worker while a removal is in flight; goja runtime state corruption.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at kernel/plugin/api_storage.go:341

			if util.ReadOnly {
				err = fmt.Errorf("The current kernel is in read-only mode, storage.remove is not allowed")
				return
			}

			abs, resolveErr := resolvePath(path)
			if resolveErr != nil {
				err = resolveErr
				return
			}
			if abs == p.storageDir {
				err = fmt.Errorf("cannot remove storage root")
				return
			}

			go func() (result any, err error) {
				defer func() {
					if r := recover(); r != nil {
						err = fmt.Errorf("panic during siyuan.storage.remove: %v", r)
					}

					p.worker.Run(func(rt *goja.Runtime) (_ any, _ error) {
						if lo.IsNil(err) {
							if resolveErr := resolve(result); resolveErr != nil {
								logging.LogErrorf("[plugin:%s] siyuan.storage.remove resolve: %v", p.Name, resolveErr)
							}
						} else {
							if rejectErr := reject(rt.NewGoError(err)); rejectErr != nil {
								logging.LogErrorf("[plugin:%s] siyuan.storage.remove reject: %v", p.Name, rejectErr)
							}
						}
						return
					}, nil)
				}()

				if removeErr := os.RemoveAll(abs); removeErr != nil {
					err = fmt.Errorf("failed to remove: %w", removeErr)

View on GitHub (pinned to 9f775e8a12)