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

  1. 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
  2. Wrap the handler body in try/catch inside the plugin so exceptions are logged instead of propagating into goja
  3. 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

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.