siyuan-note/siyuan · error
siyuan.server[%s][%s].handler is not set
Error message
siyuan.server[%s][%s].handler is not set
What it means
Thrown by getRequestHandler when globalThis.siyuan.server[scope][requestType] exists as an object but has no `handler` property that isJsValueNotNull — the registration object is present but the handler callable is missing. The plugin registered a scope/requestType entry without assigning .handler.
Source
Thrown at kernel/plugin/sandbox.go:511
// getRequestHandler retrieves the handler function and its containing object for a given scope and request type from the plugin's JS context.
func getRequestHandler(rt *goja.Runtime, scope AccessScope, requestType RequestType) (handler goja.Callable, handlerObj *goja.Object, err error) {
// Get handler object: siyuan.server[scope][requestType]
handlerObjValue, getObjErr := getJsContextValue(rt, []any{"siyuan", "server", string(scope), string(requestType)})
if getObjErr != nil {
err = getObjErr
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 {View on GitHub (pinned to 251596fc0d)
Solutions
- Add a callable `handler` to the registration object: { handler: fn }.
- Confirm handler is a function and not undefined/null (isJsValueNotNull must pass).
- Match the scope/requestType string keys to the kernel's AccessScope/RequestType constants.
Example fix
// before
globalThis.siyuan.server.network.beforeRequest = { priority: 10 }
// after
globalThis.siyuan.server.network.beforeRequest = { priority: 10, handler: (req) => { /*...*/ } } Defensive patterns
Strategy: validation
Validate before calling
// Plugin side: assert handler present before registration completes.
function registerHandler(scope: string, rt: string, fn: Function): void {
const entry = { handler: fn }
if (typeof entry.handler !== 'function') throw new Error('handler missing')
globalThis.siyuan.server[scope][rt] = entry
} Type guard
function hasHandler(v: unknown): v is { handler: Function } {
return !!v && typeof v === 'object' && typeof (v as any).handler === 'function'
} Prevention
- Always include a callable handler in the registration object.
- Use a single registration helper to enforce the shape.
- Unit-test plugin registration against the kernel's expected object layout.
When it happens
Trigger: Plugin sets globalThis.siyuan.server.network.beforeRequest = { priority: 1 } (or {}) but omits the `handler` field; or sets handler to undefined/null explicitly.
Common situations: Plugin author added metadata fields (priority, label) but forgot handler; partial/typo registration; copied a sample and dropped the handler line.
Related errors
- globalThis.siyuan.server[%s][%s] is not an object
- siyuan.server[%s][%s].handler is not a function
- path %v: value is nil
- path %v: value is %s
- path %v: expected object, got %T
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/ad1826c7c9be1b81.
Report an issue: GitHub.