siyuan-note/siyuan · error
unregistered plugin service
Error message
unregistered plugin service: %s %s
What it means
ValidatePluginServiceResponse looks up the bundle's registered endpoints for one whose method and path match and that declares a PluginService schema. This error means no such plugin-service endpoint is registered, so the response cannot be validated against any contract definition.
Solutions
- Verify the exact method and path string against the registered endpoint definitions
- Ensure the endpoint schema declares Output: PluginServiceOutput with PluginServiceOptions() so PluginService is non-nil
- Rebuild/refresh the Bundle so it contains the newly added plugin-service endpoint
Example fix
// before
bundle.ValidatePluginServiceResponse("POST", "/plugins/demo/data", ...)
// after
bundle.ValidatePluginServiceResponse("GET", "/plugins/demo/data", ...) // matches registration Defensive patterns
Strategy: validation
Validate before calling
registered := false
for _, ep := range bundle.Endpoints {
if ep.Method == method && ep.Path == path && ep.PluginService != nil {
registered = true
break
}
}
if !registered {
return fmt.Errorf("endpoint %s %s is not a registered plugin service", method, path)
} Prevention
- Keep method/path constants in one place shared by registration and validation
- Confirm the endpoint schema sets Output: PluginServiceOutput with PluginServiceOptions()
- Rebuild the Bundle after adding endpoints before running response validation
When it happens
Trigger: Calling Bundle.ValidatePluginServiceResponse("GET", "/plugins/foo/bar", ...) where /plugins/foo/bar is not in b.Endpoints, the method differs (POST vs GET), or the endpoint exists but has no PluginService declaration (validatePluginServiceDefinition failed).
Common situations: Route typos or missing leading/trailing slashes; registering the endpoint under a different HTTP method; forgetting to declare the pluginService output when building the endpoint schema; a stale bundle built before the endpoint was added.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- empty plugin response contains a body
- invalid plugin redirect status
- invalid plugin SSE status
- invalid plugin WebSocket status
- undeclared plugin admission status
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/d2f1f8e78d8bbc7f.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/apicontract/plugin_service_protocol.go:191
if len(payload) > 0 {
return fmt.Errorf("plugin service response forbids a body")
}
return nil
}
// 原始文件、代理及插件自选媒体允许任意字节,具体分支由 ValidatePluginServiceResponse 校验。
return nil
}
func (b *Bundle) ValidatePluginServiceResponse(method, path string, mode PluginServiceMode, status int, contentType string, payload []byte) error {
var found bool
for _, endpoint := range b.Endpoints {
if endpoint.Method == method && endpoint.Path == path && endpoint.PluginService != nil {
found = true
break
}
}
if !found {
return fmt.Errorf("unregistered plugin service: %s %s", method, path)
}
if err := validatePluginServiceStatus(mode, status); err != nil {
return err
}
if method == "HEAD" || status < 200 || status == 204 || status == 304 {
if len(payload) != 0 {
return fmt.Errorf("plugin service response forbids a body")
}
return nil
}
switch mode {
case PluginServiceEmpty:
if len(payload) != 0 {
return fmt.Errorf("empty plugin response contains a body")
}
case PluginServiceJSON, PluginServiceASCIIJSON, PluginServiceIndentedJSON, PluginServicePureJSON:
if !json.Valid(payload) {
return fmt.Errorf("invalid plugin JSON response")View on GitHub (pinned to 9f775e8a12)