siyuan-note/siyuan · error
siyuan.server[ ][ ].handler is not set
Error message
siyuan.server[%s][%s].handler is not set
What it means
After locating the handler container siyuan.server[scope][requestType], getRequestHandler reads its 'handler' property; if it is null, undefined, or missing (isJsValueNotNull fails), the plugin has not provided a handler and this error is returned.
Solutions
- Implement and assign the handler: obj.handler = async (request) => response
- Register only the request types the plugin actually handles; check the requested scope/requestType spelling
- Ensure the plugin's registration code runs before the first incoming request (e.g. during plugin load/open)
Example fix
// before
siyuan.server['plugin']['fetch'] = {};
// after
siyuan.server['plugin']['fetch'] = { handler: async (req) => ({ code: 0, data: null }) }; Defensive patterns
Strategy: validation
Validate before calling
const node = globalThis.siyuan?.server?.[scope]?.[requestType]; if (!node || node.handler == null) throw new Error(`handler for ${scope}/${requestType} is not registered`); Type guard
function hasHandler(v) { return v != null && v.handler != null; } Try / catch
try { await request(scope, type); } catch (e) { if (String(e).includes('.handler is not set')) { showPluginNotReadyMessage(); } else { throw e; } } Prevention
- Assign handler during plugin load before serving requests
- Register only request types the plugin implements; verify spellings
- Add a self-check after registration that every intended handler exists
When it happens
Trigger: A plugin registers siyuan.server[scope][requestType] as an object but leaves 'handler' unset, or the incoming request's scope/requestType combination has no handler registered while the container object exists (possibly empty).
Common situations: Incomplete plugin implementation, a request type the plugin intended to support but never registered, or the container created by scaffolding with a TODO placeholder.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- globalThis.siyuan.server
- failed to serialize config.
- failed to serialize inputSchema
- globalThis.siyuan.plugin.lifecycle is not an object
- globalThis.siyuan.plugin.lifecycle not found
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/ad1826c7c9be1b81.
Report an issue: GitHub.
Appendix: 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 9f775e8a12)