siyuan-note/siyuan · error

topic required

Error message

topic required

What it means

Beyond the two-argument arity check, the event method validates that the topic (first argument) is a non-empty string, since an empty topic cannot be routed to any subscriber. The promise rejects with 'topic required' when the topic is ''.

Solutions

  1. Supply a non-empty topic string as the first argument
  2. Assert/log the topic value before the call to catch empty values
  3. Skip the publish or fall back to a default topic when the value is empty
  4. Fix the upstream source (config key, data field) that yields the empty topic

Example fix

// before
await siyuan.event.publish(cfg.channel || '', payload);
// after
if (cfg.channel) { await siyuan.event.publish(cfg.channel, payload); }
Defensive patterns

Strategy: validation

Validate before calling

function publishEvent(topic, payload) {
  if (typeof topic !== 'string' || topic.length === 0) {
    throw new TypeError('event topic must be a non-empty string');
  }
  return siyuan.event.publish(topic, payload);
}

Type guard

function isNonEmptyString(v) {
  return typeof v === 'string' && v.length > 0;
}

Try / catch

try {
  await siyuan.event.publish(topic, payload);
} catch (e) {
  if (String(e.message) === 'topic required') {
    console.warn('Skipping publish: empty topic', {payload});
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling emit('', data) or emit(someVariable, data) where someVariable resolves to an empty string.

Common situations: Topics derived from config or data keys that are missing or empty; template-built topic names where a segment was blank; state not yet initialized when the call fires.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/7538f9f961daf412. Report an issue: GitHub.

Appendix: source

Thrown at kernel/plugin/api_event.go:50

		}
	}()

	event := rt.NewObject()

	lo.Must0(event.Set("handler", goja.Null()))

	lo.Must0(event.Set("emit", rt.ToValue(func(call goja.FunctionCall, rt *goja.Runtime) goja.Value {
		promise, resolve, reject := rt.NewPromise()

		var argErr error
		var topic string
		var eventData any
		if len(call.Arguments) < 2 {
			argErr = fmt.Errorf("topic and event required")
		} else {
			topic = call.Argument(0).String()
			if topic == "" {
				argErr = fmt.Errorf("topic required")
			} else {
				eventData = call.Argument(1).Export()
			}
		}

		runErr := p.worker.Run(func(rt *goja.Runtime) (result any, err error) {
			if argErr != nil {
				err = argErr
				return
			}
			p.bus.Publish(topic, eventData)
			return
		}, func(rt *goja.Runtime, result any, err error) {
			if lo.IsNil(err) {
				if resolveErr := resolve(result); resolveErr != nil {
					logging.LogErrorf("[plugin:%s] siyuan.event.emit resolve: %v", p.Name, resolveErr)
				}
			} else {

View on GitHub (pinned to 9f775e8a12)