siyuan-note/siyuan · error
siyuan.server[%s][%s].handler is not a function
Error message
siyuan.server[%s][%s].handler is not a function
What it means
Thrown by getRequestHandler when globalThis.siyuan.server[scope][requestType].handler exists and is non-null but goja.AssertFunction fails — the handler is present but not a JS function (e.g. a string, object, or number). The handler callable contract is violated.
Source
Thrown at kernel/plugin/sandbox.go:517
return
}
handlerObj = handlerObjValue.ToObject(rt)
if handlerObj == nil {
err = fmt.Errorf("globalThis.siyuan.server[%s][%s] is not an object", scope, requestType)
return
}
// Get handler: siyuan.server[scope][requestType].handler
handlerValue := handlerObj.Get("handler")
if !isJsValueNotNull(handlerValue) {
err = fmt.Errorf("siyuan.server[%s][%s].handler is not set", scope, requestType)
return
}
handler, ok := goja.AssertFunction(handlerValue)
if !ok {
err = fmt.Errorf("siyuan.server[%s][%s].handler is not a function", scope, requestType)
return
}
return
}
// requestGoToJs converts a Go Request to a JavaScript value.
func requestGoToJs(p *KernelPlugin, rt *goja.Runtime, request *Request) (jsRequest goja.Value, err error) {
// convert body raw data to js object
if data, ok := request.Request.Body.Data.(*[]byte); ok && data != nil {
request.Request.Body.Data, err = NewDataObject(p, rt, *data)
if err != nil {
return
}
}
// convert body form files data to js object
if request.Request.Body.Form != nil {View on GitHub (pinned to 251596fc0d)
Solutions
- Assign an actual function to the handler property.
- After refactor, confirm the referenced symbol is still a function and not shadowed by a string/config.
- Add a typeof === 'function' guard in the plugin before registration.
Example fix
// before
globalThis.siyuan.server.network.beforeRequest = { handler: 'onBeforeRequest' }
// after
globalThis.siyuan.server.network.beforeRequest = { handler: (req) => { /*...*/ } } Defensive patterns
Strategy: type-guard
Validate before calling
// Plugin side: ensure handler is a function before assigning.
function setHandler(scope: string, rt: string, fn: unknown): void {
if (typeof fn !== 'function') throw new Error('handler must be a function')
globalThis.siyuan.server[scope][rt] = { handler: fn }
} Type guard
function isCallable(v: unknown): v is (...a: any[]) => any {
return typeof v === 'function'
} Prevention
- Assign only functions to handler; never strings/numbers/objects.
- After refactors, confirm the referenced symbol is still a function.
- Add typeof === 'function' guards in the registration helper.
When it happens
Trigger: Plugin assigns handler to a non-function value: server.network.beforeRequest = { handler: 'doStuff' } or { handler: 42 } or { handler: {} }.
Common situations: Plugin author stored a config/label in handler by mistake; refactor renamed a function and left a stale non-function reference; serialization stored a string identifier instead of the function.
Related errors
- globalThis.siyuan.server[%s][%s] is not an object
- path %v: expected object, got %T
- expected promise object, got %T
- siyuan.server[%s][%s].handler is not set
- path %v: value is nil
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/dd8da81a7bbfe366.
Report an issue: GitHub.