{"record":{"id":"9b0f5322ae480126","repo":"siyuan-note/siyuan","slug":"panic-during-siyuan-storage-list-v","errorCode":null,"errorMessage":"panic during siyuan.storage.list: %v","messagePattern":"panic during siyuan\\.storage\\.list: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/plugin/api_storage.go","lineNumber":409,"sourceCode":"\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\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\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.list: %v\", r)\n\t\t\t\t\t}\n\t\t\t\t\tp.worker.Run(func(rt *goja.Runtime) (_ any, _ error) {\n\t\t\t\t\t\tif lo.IsNil(err) {\n\t\t\t\t\t\t\tif resolveErr := resolve(result); resolveErr != nil {\n\t\t\t\t\t\t\t\tlogging.LogErrorf(\"[plugin:%s] siyuan.storage.list resolve: %v\", p.Name, resolveErr)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tif rejectErr := reject(rt.NewGoError(err)); rejectErr != nil {\n\t\t\t\t\t\t\t\tlogging.LogErrorf(\"[plugin:%s] siyuan.storage.list reject: %v\", p.Name, rejectErr)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn\n\t\t\t\t\t}, nil)\n\t\t\t\t}()\n\n\t\t\t\tentries, readErr := os.ReadDir(abs)\n\t\t\t\tif readErr != nil {\n\t\t\t\t\terr = fmt.Errorf(\"failed to read directory: %w\", readErr)","sourceCodeStart":391,"sourceCodeEnd":427,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/plugin/api_storage.go#L391-L427","documentation":"A safety net that converts an unexpected panic inside the siyuan.storage.list goroutine into a Promise rejection. The deferred recover() catches any panic (nil deref, slice OOB, etc.) and formats it. In normal operation it should never trigger; it indicates a bug in the kernel's list path or a corrupted directory entry.","triggerScenarios":"A panic occurs after os.ReadDir or while building the results slice, e.g. entry.Info() returning something that breaks a later assumption, or memory corruption in the goja runtime bridging.","commonSituations":"Encountered alongside a kernel bug report; not something plugin code produces by design. Rare and indicates a bug in SiYuan itself.","solutions":["Report the panic value and plugin name to the SiYuan issue tracker with the storage path that triggered it.","Wrap your list call in try/catch and fall back to a cached/empty result.","Reproduce with the latest kernel version to see if the panic is already fixed.","Inspect the kernel log for the matching siyuan.storage.list reject line for the panic detail."],"exampleFix":"// before\nconst entries = await siyuan.storage.list(dir);\n\n// after\nlet entries;\ntry {\n  entries = await siyuan.storage.list(dir);\n} catch (e) {\n  console.error('storage.list panicked, using fallback', e);\n  entries = [];\n}","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { return await siyuan.storage.list(dir); } catch (e) { console.error('storage.list unrecoverable', e); return []; }","preventionTips":["Treat a panic here as a kernel bug; report with the path and plugin name.","Keep a fallback (cached/empty) so the plugin degrades gracefully.","Keep plugins and kernel on the latest version."],"tags":["plugin","storage","panic","internal-bug"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}