{"record":{"id":"4f7384663d2bb0cc","repo":"siyuan-note/siyuan","slug":"event-data-is-required","errorCode":null,"errorMessage":"event.data is required","messagePattern":"event\\.data is required","errorType":"exception","errorClass":"GoError","httpStatus":null,"severity":"error","filePath":"kernel/plugin/plugin.go","lineNumber":1385,"sourceCode":"\n\t\tinvokePortHook := func(name string, args ...goja.Value) {\n\t\t\thook := port.Get(name)\n\t\t\tif fn, ok := goja.AssertFunction(hook); ok {\n\t\t\t\tif _, callErr := fn(port, args...); callErr != nil {\n\t\t\t\t\tlogging.LogErrorf(\"[plugin:%s] sse server port hook %q: %v\", p.Name, name, callErr)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tport_send := rt.ToValue(func(call goja.FunctionCall, rt *goja.Runtime) goja.Value {\n\t\t\tif eventJs := call.Argument(0); isJsValueNotNull(eventJs) {\n\t\t\t\tif eventObj := eventJs.ToObject(rt); eventObj != nil {\n\t\t\t\t\te := sse.Event{}\n\n\t\t\t\t\tif data := eventObj.Get(\"data\"); isJsValueNotUndefined(data) {\n\t\t\t\t\t\te.Data = data.Export()\n\t\t\t\t\t} else {\n\t\t\t\t\t\tpanic(rt.NewGoError(fmt.Errorf(\"event.data is required\")))\n\t\t\t\t\t}\n\n\t\t\t\t\tif event := eventObj.Get(\"event\"); goja.IsString(event) {\n\t\t\t\t\t\te.Event = event.String()\n\t\t\t\t\t}\n\n\t\t\t\t\tif id := eventObj.Get(\"id\"); goja.IsString(id) {\n\t\t\t\t\t\te.Id = id.String()\n\t\t\t\t\t}\n\n\t\t\t\t\tif retry := eventObj.Get(\"retry\"); goja.IsNumber(retry) {\n\t\t\t\t\t\te.Retry = uint(retry.ToInteger())\n\t\t\t\t\t}\n\n\t\t\t\t\tevents.In <- e\n\t\t\t\t\treturn goja.Undefined()\n\t\t\t\t}\n\t\t\t}","sourceCodeStart":1367,"sourceCodeEnd":1403,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/plugin/plugin.go#L1367-L1403","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Always include a data property in the object passed to port.send, even if empty: {data: ''}","Guard the call: if (event && event.data !== undefined) port.send(event)","Fix renamed fields so the payload is under data, not message/payload/body","Serialize non-string payloads yourself if you need a specific wire format (the kernel exports data as-is)"],"exampleFix":"// before\nport.send({ event: \"progress\" });\n// after\nport.send({ event: \"progress\", data: JSON.stringify({ percent: 50 }) });","handlingStrategy":"validation","validationCode":"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\"); }","typeGuard":"const hasSseData = (ev) => !!ev && typeof ev === \"object\" && ev.data !== undefined;","tryCatchPattern":"try { port.send(ev); } catch (e) { if (String(e).includes(\"event.data is required\")) { port.send({ ...ev, data: \"\" }); } else { throw e; } }","preventionTips":["Always set data in every event object passed to port.send","Keep the canonical field name data; do not rename to payload/message","Write a helper builder (makeEvent(data, opts)) so ad-hoc objects are not constructed","Add unit tests asserting each emitted event includes data"],"tags":["sse","plugin-api","validation","missing-field"],"backgroundTag":"missing-required-argument","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}