siyuan-note/siyuan · error

The current kernel is in read-only mode, storage.remove is n

Error message

The current kernel is in read-only mode, storage.remove is not allowed

What it means

Thrown by siyuan.storage.remove() when util.ReadOnly is true. The kernel can boot in read-only mode to forbid all mutations; in that mode deletions are rejected before path resolution or filesystem access. The check runs after the argument-count guard but before the storage-root guard.

Source

Thrown at kernel/plugin/api_storage.go:324

	// siyuan.storage.remove(path) -> Promise<void>
	lo.Must0(storage.Set("remove", rt.ToValue(func(call goja.FunctionCall, rt *goja.Runtime) goja.Value {
		promise, resolve, reject := rt.NewPromise()

		var argErr error
		var path string
		if len(call.Arguments) < 1 {
			argErr = fmt.Errorf("path required")
		} else {
			path = call.Argument(0).String()
		}

		runErr := p.worker.Run(func(rt *goja.Runtime) (result any, err error) {
			if argErr != nil {
				err = argErr
				return
			}
			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)
					}

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Detect read-only mode at startup and hide or disable delete features.
  2. Wrap remove in try/catch and degrade gracefully when the rejection indicates read-only mode.
  3. Inform the user that the operation requires a writable kernel.

Example fix

// before
await siyuan.storage.remove(path);
// after
try {
  await siyuan.storage.remove(path);
} catch (e) {
  if (String(e).includes('read-only mode')) {
    // skip deletion silently or notify the user
  } else {
    throw e;
  }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Reuse the read-only probe from error 1012 and skip remove when readOnly is true.

Try / catch

try {
  await siyuan.storage.remove(path);
} catch (e) {
  if (/read-only mode/.test(String(e))) { /* skip deletion */ return; }
  throw e;
}

Prevention

When it happens

Trigger: Calling storage.remove on a read-only kernel instance (published/preview server, demo environment, workspace mounted read-only). Every remove call rejects regardless of the target path.

Common situations: Plugin works on a normal kernel but is later deployed on a publishing server that runs read-only; user booted the kernel with a read-only flag for safety.

Related errors


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