{"record":{"id":"7b4b032c92d84052","repo":"siyuan-note/siyuan","slug":"the-current-kernel-is-in-read-only-mode-storage-r","errorCode":null,"errorMessage":"The current kernel is in read-only mode, storage.remove is not allowed","messagePattern":"The current kernel is in read-only mode, storage\\.remove is not allowed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/plugin/api_storage.go","lineNumber":324,"sourceCode":"\t// siyuan.storage.remove(path) -> Promise<void>\n\tlo.Must0(storage.Set(\"remove\", rt.ToValue(func(call goja.FunctionCall, rt *goja.Runtime) goja.Value {\n\t\tpromise, resolve, reject := rt.NewPromise()\n\n\t\tvar argErr error\n\t\tvar path string\n\t\tif len(call.Arguments) < 1 {\n\t\t\targErr = fmt.Errorf(\"path required\")\n\t\t} else {\n\t\t\tpath = call.Argument(0).String()\n\t\t}\n\n\t\trunErr := p.worker.Run(func(rt *goja.Runtime) (result any, err error) {\n\t\t\tif argErr != nil {\n\t\t\t\terr = argErr\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif util.ReadOnly {\n\t\t\t\terr = fmt.Errorf(\"The current kernel is in read-only mode, storage.remove is not allowed\")\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tabs, resolveErr := resolvePath(path)\n\t\t\tif resolveErr != nil {\n\t\t\t\terr = resolveErr\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif abs == p.storageDir {\n\t\t\t\terr = fmt.Errorf(\"cannot remove storage root\")\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tgo func() (result any, err error) {\n\t\t\t\tdefer func() {\n\t\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\t\terr = fmt.Errorf(\"panic during siyuan.storage.remove: %v\", r)\n\t\t\t\t\t}","sourceCodeStart":306,"sourceCodeEnd":342,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/plugin/api_storage.go#L306-L342","documentation":"siyuan.storage.remove is a mutating plugin-storage API. When the SiYuan kernel runs in read-only mode (util.ReadOnly is true, e.g. while a sync/data operation holds exclusive access or the workspace is opened read-only), the API refuses to delete files and rejects the returned Promise with this message. This guards plugin data from being deleted while the kernel cannot safely persist changes.","triggerScenarios":"A plugin calls siyuan.storage.remove(path) while the kernel is in read-only mode. In the Go kernel this check runs before path resolution, so even a valid path is rejected. Typically hit when SiYuan is running with the read-only flag or during states where writes are disabled.","commonSituations":"Workspace opened in read-only mode; kernel started with a read-only configuration; plugin code that assumes storage is always writable and calls remove unconditionally (e.g. cleanup logic on plugin load).","solutions":["Check whether the kernel is in read-only mode before calling siyuan.storage.remove (kernel.plugin supports a read-only query; or catch the rejection and defer the removal)","Wrap remove calls in try/catch and queue deletions for when read-only mode ends","Avoid destructive storage cleanup on plugin startup; only remove entries the user explicitly deletes","If read-only mode is unexpected, restart the kernel/workspace with write access enabled"],"exampleFix":"// before\nawait siyuan.storage.remove(\"/tmp/cache.json\");\n\n// after\ntry {\n  await siyuan.storage.remove(\"/tmp/cache.json\");\n} catch (e) {\n  if (String(e).includes(\"read-only mode\")) {\n    console.warn(\"deferred removal: kernel is read-only\");\n  } else {\n    throw e;\n  }\n}","handlingStrategy":"try-catch","validationCode":"// guard: skip removal while kernel is read-only\nif (typeof siyuan?.kernel?.isReadOnly === \"function\" && siyuan.kernel.isReadOnly()) {\n  return; // defer removal\n}","typeGuard":null,"tryCatchPattern":"try {\n  await siyuan.storage.remove(path);\n} catch (e) {\n  if (String(e).includes(\"read-only mode\")) {\n    // queue for later\n  } else {\n    throw e;\n  }\n}","preventionTips":["Never perform destructive storage cleanup unconditionally at plugin startup","Check kernel read-only state before mutating storage APIs","Catch and classify rejections from storage.remove"],"tags":["plugin","storage","read-only","filesystem"],"backgroundTag":"permission-denied","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}