siyuan-note/siyuan · error · GoError

event.data is required

Error message

event.data is required

What it means

The SSE port's send(event) function requires the event object to carry a data field. If port.send is called with an object that has no 'data' property (or data is undefined), the kernel panics the JS call with a GoError 'event.data is required'. Event fields event, id, and retry are optional, but data is mandatory for an SSE stream frame.

Solutions

  1. Always include a data property in the object passed to port.send, even if empty: {data: ''}
  2. Guard the call: if (event && event.data !== undefined) port.send(event)
  3. Fix renamed fields so the payload is under data, not message/payload/body
  4. Serialize non-string payloads yourself if you need a specific wire format (the kernel exports data as-is)

Example fix

// before
port.send({ event: "progress" });
// after
port.send({ event: "progress", data: JSON.stringify({ percent: 50 }) });
Defensive patterns

Strategy: validation

Validate before calling

function assertSseEvent(ev) { if (!ev || typeof ev !== "object") throw new Error("send requires an event object"); if (ev.data === undefined) throw new Error("event.data is required"); }

Type guard

const hasSseData = (ev) => !!ev && typeof ev === "object" && ev.data !== undefined;

Try / catch

try { port.send(ev); } catch (e) { if (String(e).includes("event.data is required")) { port.send({ ...ev, data: "" }); } else { throw e; } }

Prevention

When it happens

Trigger: Calling port.send({event: 'log'}) or port.send({}) without a data key; passing an object whose data was conditionally assigned and ended up undefined; calling port.send(undefined/null plus a non-object) is a different error (invalid event object), this one is specifically an object without data.

Common situations: Plugin authors building events dynamically and forgetting to set data; refactors renaming data to payload/message while keeping port.send; forwarding upstream objects that lack data.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at kernel/plugin/plugin.go:1385

		invokePortHook := func(name string, args ...goja.Value) {
			hook := port.Get(name)
			if fn, ok := goja.AssertFunction(hook); ok {
				if _, callErr := fn(port, args...); callErr != nil {
					logging.LogErrorf("[plugin:%s] sse server port hook %q: %v", p.Name, name, callErr)
				}
			}
		}

		port_send := rt.ToValue(func(call goja.FunctionCall, rt *goja.Runtime) goja.Value {
			if eventJs := call.Argument(0); isJsValueNotNull(eventJs) {
				if eventObj := eventJs.ToObject(rt); eventObj != nil {
					e := sse.Event{}

					if data := eventObj.Get("data"); isJsValueNotUndefined(data) {
						e.Data = data.Export()
					} else {
						panic(rt.NewGoError(fmt.Errorf("event.data is required")))
					}

					if event := eventObj.Get("event"); goja.IsString(event) {
						e.Event = event.String()
					}

					if id := eventObj.Get("id"); goja.IsString(id) {
						e.Id = id.String()
					}

					if retry := eventObj.Get("retry"); goja.IsNumber(retry) {
						e.Retry = uint(retry.ToInteger())
					}

					events.In <- e
					return goja.Undefined()
				}
			}

View on GitHub (pinned to 9f775e8a12)