siyuan-note/siyuan · error
handler did not return an object
Error message
handler did not return an object
What it means
Returned when an HTTP request handler's resolved Promise value cannot be turned into a JS object via ToObject (result is null/undefined/number/string). The kernel requires the handler to return a plain object shaped like { status, headers, body } so it can extract the response.
Source
Thrown at kernel/plugin/plugin.go:928
err = getHandlerErr
return
}
jsRequest, convertErr := requestGoToJs(p, rt, request)
if convertErr != nil {
err = convertErr
return
}
invokeFunction(func(rt *goja.Runtime, result *CallResult) {
if result.Error != nil {
done <- &handleResult{Error: result.Error}
return
}
responseObj := result.Value.ToObject(rt)
if responseObj == nil {
done <- &handleResult{Error: fmt.Errorf("handler did not return an object")}
return
}
// convert response.body?.raw?.data from (string | Buffer | ArrayBuffer) to []byte
var raw *[]byte
if bodyValue := responseObj.Get("body"); isJsValueNotNull(bodyValue) {
// response.body
if bodyObj := bodyValue.ToObject(rt); bodyObj != nil {
if rawValue := bodyObj.Get("raw"); isJsValueNotNull(rawValue) {
// response.body.raw
if rawObj := rawValue.ToObject(rt); rawObj != nil {
if dataValue := rawObj.Get("data"); isJsValueNotNull(dataValue) {
// response.body.raw.data
dataBytes, convertErr := jsValueToBytes(rt, dataValue)
if convertErr == nil {
raw = &dataBytes
rawObj.Set("data", goja.Null())
}View on GitHub (pinned to 251596fc0d)
Solutions
- Make the handler always return a response object: return { status: 200, headers: {}, body: { raw: { mime: 'text/plain', data: 'ok' } } }.
- Add an explicit default response at the end of the handler so no code path falls through.
- Type the handler return in TS as Response so the compiler flags missing returns.
Example fix
// before
server.onRequest('GET', '/x', async (req) => {
if (req.query.bad) return; // undefined -> error
return { status: 200, body: { raw: { mime: 'text/plain', data: 'ok' } } };
});
// after
server.onRequest('GET', '/x', async (req) => {
if (req.query.bad) return { status: 400, body: { raw: { mime: 'text/plain', data: 'bad' } } };
return { status: 200, body: { raw: { mime: 'text/plain', data: 'ok' } } };
}); Defensive patterns
Strategy: type-guard
Validate before calling
function isResponseObject(v: unknown): v is { status: number; headers?: Record<string,string>; body?: unknown } { return !!v && typeof v === 'object' && typeof (v as any).status === 'number'; } Type guard
function isResponseObject(v: unknown): v is { status: number; headers?: Record<string,string>; body?: unknown } { return !!v && typeof v === 'object' && typeof (v as any).status === 'number'; } Prevention
- Always return a response object from every code path in the handler.
- Type the handler return so TS flags missing returns.
- Add a default response as the last statement.
When it happens
Trigger: An onRequest HTTP handler returns undefined, null, a primitive, or forgets to return the response object, so result.Value.ToObject(rt) yields nil.
Common situations: Handler function missing a return statement, returning a fetch Response directly instead of a plain {status, headers, body} object, or an early return path that yields nothing.
Related errors
- invalid response format: %v
- event.data is required
- failed to convert request value to object
- WebSocket is not open (state: %d)
- invalid event object
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/c15e9ce5b922907d.
Report an issue: GitHub.