{"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":null,"httpStatus":null,"severity":"error","filePath":"kernel/plugin/plugin.go","lineNumber":1384,"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":1366,"sourceCodeEnd":1402,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/plugin/plugin.go#L1366-L1402","documentation":"Panicked (converted to a Go error via rt.NewGoError) when the SSE port.send() receives an event object that has no data field (data is undefined). The SSE spec requires a data field for every event, so the kernel treats its absence as a hard error rather than silently dropping the event.","triggerScenarios":"Plugin calls port.send({ event: 'ping' }) or port.send({}) without a data property; or data is set to undefined explicitly.","commonSituations":"Building an event object conditionally and forgetting to set data on a branch; sending a comment-style event without data.","solutions":["Always include data: port.send({ data: 'hello', event: 'ping' }).","Default data to an empty string if you genuinely want an empty payload: port.send({ data: '' }).","Validate the event object shape before calling send."],"exampleFix":"// before\nport.send({ event: name });\n\n// after\nport.send({ event: name, data: payload ?? '' });","handlingStrategy":"validation","validationCode":"function hasData(e: any): boolean { return !!e && typeof e === 'object' && 'data' in e && e.data !== undefined; }","typeGuard":"function isSseEvent(e: unknown): e is { data: unknown; event?: string; id?: string; retry?: number } { return !!e && typeof e === 'object' && 'data' in (e as any) && (e as any).data !== undefined; }","tryCatchPattern":"try { port.send(event); } catch (e) { if (/event\\.data is required/.test(String(e))) { port.send({ ...event, data: '' }); return; } throw e; }","preventionTips":["Always include a data field on every SSE event.","Default data to '' when you want an empty payload.","Validate the event object before send."],"tags":["plugin","server","sse","validation","contract"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}