{"record":{"id":"5dc9d929cc0470f4","repo":"siyuan-note/siyuan","slug":"goja-panic-during-close-runtime-v","errorCode":null,"errorMessage":"goja panic during close runtime: %v","messagePattern":"goja panic during close runtime: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"kernel/plugin/plugin.go","lineNumber":227,"sourceCode":"\t\tif _, runErr := rt.RunScript(p.file, p.Kernel.JS); runErr != nil {\n\t\t\terr = fmt.Errorf(\"RunScript: %v\", runErr)\n\t\t\treturn\n\t\t}\n\t})\n\tp.runtime.Start()\n\treturn\n}\n\n// Eval evaluates JavaScript code in the plugin's goja runtime, returning the result or error.\nfunc (p *KernelPlugin) Eval(rt *goja.Runtime, code string) (goja.Value, error) {\n\treturn rt.RunScript(p.file, code)\n}\n\n// close interrupts the goja runtime and clears the pointer.\nfunc (p *KernelPlugin) close() (err error) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\terr = fmt.Errorf(\"goja panic during close runtime: %v\", r)\n\t\t}\n\t}()\n\n\truntime := p.runtime\n\tp.runtime = nil\n\tif runtime != nil {\n\t\truntime.Stop() // Stops the event loop and waits for it to finish.\n\t\t// p.runtime.Terminate() // Interrupts the runtime and causes all executing code to throw an exception.\n\t}\n\treturn\n}\n\n// error sets the plugin state to errored and frees the goja runtime.\nfunc (p *KernelPlugin) error() {\n\tif p.cancel != nil {\n\t\tp.cancel()\n\t}\n\tp.closeStorageWatcher()","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/plugin/plugin.go#L209-L245","documentation":"`KernelPlugin.close` stops the plugin's goja event loop via `runtime.Stop()`. A Go panic during this shutdown (e.g. stopping an already-stopped or mid-callback event loop) is recovered and returned as `goja panic during close runtime: %v`. It indicates a problem tearing down the plugin runtime, usually during plugin stop or error handling.","triggerScenarios":"Calling close() when the event loop is in an unexpected state — double stop, Stop racing with a pending worker task, or a panic inside eventloop.Stop due to runtime inconsistency.","commonSituations":"Rapid disable/enable cycles on the same plugin, a plugin error path calling p.error() which invokes close while the loop is already terminating, or kernel shutdown while plugins are mid-callback.","solutions":["Check logs for a preceding plugin error that triggered this during error handling","Avoid rapid enable/disable toggling of the plugin","Restart the SiYuan kernel to clear stuck runtimes","If reproducible, report with the panic value and plugin name"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := plugin.Stop(); err != nil { log.Warnf(\"plugin stop reported: %v (runtime may already be closed)\", err) }","preventionTips":["Avoid toggling plugin enable/disable in rapid succession","Let in-flight async tasks finish before stopping plugins","Treat close errors during shutdown as non-fatal warnings","Restart the kernel if runtimes appear stuck"],"tags":["goja","panic-recovery","plugin-lifecycle","shutdown"],"backgroundTag":"internal-invariant-violation","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}