siyuan-note/siyuan · error
invalid plugin service response options
Error message
invalid plugin service response options
What it means
An endpoint declared as a plugin service must use PluginServiceContent as its Data type and must not combine the plugin-service output with any other response options: SSE, Proxy, WebSocket definitions, DataOnError, or a custom ErrorStatus. validatePluginServiceDefinition returns this error when any of these conflicting options are present, because plugin service responses carry their mode/status in private response metadata set by the StreamPluginService-style constructors, not in the shared option fields.
Solutions
- Set definition.Data to reflect.TypeFor[apicontract.PluginServiceContent]()
- Remove SSE, Proxy, WebSocket, DataOnError, and ErrorStatus from the plugin-service definition
- If the endpoint needs those other options, it is not a plugin service — use the appropriate output mode instead
Example fix
// before
definition := apicontract.Definition{Output: apicontract.PluginServiceOutput, Data: reflect.TypeFor[MyPayload](), ErrorStatus: 500, PluginService: &opts.PluginService}
// after
definition := apicontract.Definition{Output: apicontract.PluginServiceOutput,
Data: reflect.TypeFor[apicontract.PluginServiceContent](),
PluginService: &opts.PluginService} Defensive patterns
Strategy: validation
Validate before calling
if definition.Output == apicontract.PluginServiceOutput {
if definition.Data != reflect.TypeFor[apicontract.PluginServiceContent]() ||
definition.SSE != nil || definition.Proxy != nil || definition.WebSocket != nil ||
definition.DataOnError || definition.ErrorStatus != 0 {
return errors.New("plugin service definitions must use PluginServiceContent and no other response options")
}
} Try / catch
if err := apicontract.BuildBundle(endpoints); err != nil {
if strings.Contains(err.Error(), "response options") { log.Fatalf("conflicting endpoint options: %v", err) }
return err
} Prevention
- When converting an endpoint to plugin service output, strip SSE/Proxy/WebSocket/DataOnError/ErrorStatus in the same change
- Keep plugin service payload typing in the stream callback, not in Data
- Add a definition-lint unit test for every endpoint table
When it happens
Trigger: BuildBundle validates a Definition whose Output is PluginServiceOutput but whose Data is a concrete payload type (not reflect.TypeFor[PluginServiceContent]()), or which also sets SSE, Proxy, WebSocket, DataOnError, or ErrorStatus.
Common situations: Converting an ordinary JSON endpoint into a plugin service by only changing the Output mode while leaving Data typed and ErrorStatus set, mixing SSE/event features into a plugin service endpoint, or merging definitions from two templates.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- plugin service output requires a protocol declaration
- invalid plugin service protocol variants
- 26
- agent HTTP tools support HTTP, HTTPS and SOCKS5 proxies
- AI configuration is unavailable
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/39ca7eee7ea2a13e.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/apicontract/plugin_service_protocol.go:125
panic("plugin service requires a selected response mode")
}
return 200
}
if err := validatePluginServiceStatus(response.pluginServiceMode, response.httpStatus); err != nil {
panic(err)
}
return response.httpStatus
}
func validatePluginServiceDefinition(definition Definition) error {
if (definition.Output == PluginServiceOutput) != (definition.PluginService != nil) {
return fmt.Errorf("plugin service output requires a protocol declaration")
}
if definition.PluginService == nil {
return nil
}
if definition.Data != reflect.TypeFor[PluginServiceContent]() || definition.SSE != nil || definition.Proxy != nil || definition.WebSocket != nil || definition.DataOnError || definition.ErrorStatus != 0 {
return fmt.Errorf("invalid plugin service response options")
}
if !reflect.DeepEqual(definition.PluginService, PluginServiceOptions().PluginService) {
return fmt.Errorf("invalid plugin service protocol variants")
}
return nil
}
func validatePluginServiceStatus(mode PluginServiceMode, status int) error {
if status < 100 || status > 999 {
return fmt.Errorf("invalid plugin service HTTP status: %d", status)
}
known := false
for _, variant := range PluginServiceOptions().PluginService.Variants {
if variant.Mode == mode {
known = true
break
}
}View on GitHub (pinned to 9f775e8a12)