siyuan-note/siyuan · error
goja panic during dispatchEvent: %v
Error message
goja panic during dispatchEvent: %v
What it means
dispatchEvent installs a Go recover() so that a panic raised inside the goja runtime while calling the plugin's globalThis.siyuan.event.on hook is converted into this error instead of crashing the kernel. The %v carries the recovered panic value, which is usually a *goja.Object exception or a goja-thrown JS error.
Source
Thrown at kernel/plugin/sandbox.go:328
cursor = obj.Get(k)
path = fmt.Sprintf("%s.%s", path, k)
case int:
cursor = obj.Get(strconv.Itoa(k))
path = fmt.Sprintf("%s[%d]", path, k)
default:
err = fmt.Errorf("unsupported path type: %T", key)
return
}
}
value = cursor
return
}
// dispatchEvent calls the globalThis.siyuan.event.on hook with the given event object.
func dispatchEvent(p *KernelPlugin, rt *goja.Runtime, e any) (async bool, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("goja panic during dispatchEvent: %v", r)
}
}()
event, err := getJsContextValue(rt, []any{"siyuan", "event"})
if err != nil {
return
}
if event == nil {
err = fmt.Errorf("globalThis.siyuan.event not found")
return
}
if goja.IsUndefined(event) || goja.IsNull(event) {
err = fmt.Errorf("globalThis.siyuan.event is %s", event.String())
return
}
eventObj := event.ToObject(rt)
if eventObj == nil {View on GitHub (pinned to 8641553a1f)
Solutions
- Read the %v detail in the error to identify the JS exception, and fix the throwing code in the plugin's siyuan.event.on handler
- Wrap the handler body in try/catch inside the plugin so exceptions are logged instead of propagating into goja
- Verify siyuan.event.on is a function (typeof siyuan.event.on === 'function') before registering event listeners
Example fix
// before (plugin JS)
siyuan.event.on(eventName, e => processEvent(e.detail.id));
// after
siyuan.event.on(eventName, e => { try { processEvent(e && e.detail && e.detail.id); } catch (err) { console.error(err); } }); Defensive patterns
Strategy: try-catch
Validate before calling
console.assert(typeof siyuan !== 'undefined' && siyuan.event && typeof siyuan.event.on === 'function', 'event hook missing');
Type guard
const hasEventHook = () => typeof siyuan !== 'undefined' && siyuan.event != null && typeof siyuan.event.on === 'function';
Try / catch
try { const r = dispatchEvent(p, rt, e); if (r.err != nil) { log.Warnf("event dispatch failed: %v", r.err) } } catch (err) { log.Warnf("event dispatch panicked: %v", err) } Prevention
- Wrap every plugin event handler body in try/catch
- Never throw from top-level handler code; log and return instead
- Test handlers with malformed/missing event payloads before release
When it happens
Trigger: The plugin's siyuan.event.on handler (or code it calls) throws an uncaught JS exception or goja panics while dispatchEvent invokes handler(event, eventJs).
Common situations: Plugin event handlers with bugs: accessing properties of undefined, calling a non-function hook, infinite recursion, or a handler that itself calls kernel APIs which throw.
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@8641553a1f (2026-09-11).
Data as JSON: /api/errors/a4f7675855f4e542.
Report an issue: GitHub.