siyuan-note/siyuan · error · GoError

invalid event object

Error message

invalid event object

What it means

The SSE port's send function falls through to panic with 'invalid event object' when its first argument is null/undefined or cannot be converted to a JS object. Unlike 'event.data is required' (object present but missing data), this error means send() did not receive a usable object at all.

Solutions

  1. Always pass a plain object to port.send: port.send({data: ...})
  2. Guard the call site: if (payload) port.send({data: payload})
  3. Ensure variables hold the event object, not a resolved inner value that may be undefined
  4. Wrap sends in try/catch so a transient bad payload does not kill the SSE handler

Example fix

// before
const result = await compute();
port.send(result);
// after
const result = await compute();
if (result != null) { port.send({ data: JSON.stringify(result) }); }
Defensive patterns

Strategy: validation

Validate before calling

function assertEventObject(ev) { if (ev === null || ev === undefined || typeof ev !== "object") throw new Error("port.send requires an event object"); }

Type guard

const isEventObject = (v) => v !== null && typeof v === "object";

Try / catch

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

Prevention

When it happens

Trigger: Calling port.send() with no arguments; port.send(null) or port.send(undefined); passing a primitive (number/string/boolean) where an event object is expected and ToObject yields nil; passing a value that is not null-checked before ToObject.

Common situations: Async code paths that pass a possibly-empty result variable into port.send; spreading/destructuring mistakes that yield undefined; API misuse after reading examples of the fetch-style API instead of the SSE port API.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at kernel/plugin/plugin.go:1404

					}

					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()
				}
			}
			panic(rt.NewGoError(fmt.Errorf("invalid event object")))
		})

		port_close := rt.ToValue(func(call goja.FunctionCall, rt *goja.Runtime) goja.Value {
			doClose()
			return goja.Undefined()
		})

		lo.Must0(port.Set("onopen", goja.Null()))
		lo.Must0(port.Set("onclose", goja.Null()))

		lo.Must0(port.Set("send", port_send))
		lo.Must0(port.Set("close", port_close))

		lo.Must0(ObjectSeal(rt, port))

		lo.Must0(jsRequestObj.Set("port", port))

		invokeFunction(func(_ *goja.Runtime, result *CallResult) {

View on GitHub (pinned to 9f775e8a12)