siyuan-note/siyuan · error
invalid plugin SSE status
Error message
invalid plugin SSE status
What it means
SSE-mode plugin service responses may only use status 200 (stream started) or 500 (stream failed to start); validatePluginServiceStatus rejects anything else. This guarantees the event-stream contract only ever advertises a successful stream or an explicit server failure.
Solutions
- Return 200 when the event stream starts, 500 when it cannot
- Handle auth/rejection logic before entering the SSE variant, or use 500 for unrecoverable stream-start failures
- Use a different variant (e.g. admission or JSON) for gating responses
Example fix
// before StreamPluginService(PluginServiceSSE, http.StatusNoContent, serve) // after StreamPluginService(PluginServiceSSE, http.StatusOK, serve)
Defensive patterns
Strategy: validation
Validate before calling
func validSSEStatus(status int) bool {
return status == http.StatusOK || status == http.StatusInternalServerError
} Try / catch
defer func() {
if rec := recover(); rec != nil {
log.Printf("invalid SSE status: %v", rec)
}
}() // around StreamPluginService(PluginServiceSSE, ...) Prevention
- Only 200 or 500 for SSE responses
- Perform gating/auth before switching to SSE mode
- Cover the stream-failure (500) path in tests
When it happens
Trigger: Calling StreamPluginService(PluginServiceSSE, status, serve) or ValidatePluginServiceResponse with sse mode and a status other than 200 or 500 (e.g. 204, 404, or 403).
Common situations: Trying to signal 'no events' with 204; using 401/403 to gate an SSE stream; copying a redirect status into an SSE response.
Related errors
- invalid plugin redirect status
- invalid plugin WebSocket status
- undeclared plugin admission status
- empty plugin response contains a body
- invalid plugin service HTTP status
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/2a4a595f3aac1511.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/apicontract/plugin_service_protocol.go:162
if !known {
return fmt.Errorf("unknown plugin service mode: %s", mode)
}
switch mode {
case PluginServiceAdmission:
if status != 400 && status != 404 && status != 500 && status != 503 {
return fmt.Errorf("undeclared plugin admission status")
}
case PluginServiceRedirect:
if status != 201 && (status < 300 || status > 308) {
return fmt.Errorf("invalid plugin redirect status")
}
case PluginServiceWebSocket:
if status != 101 && status != 400 && status != 500 {
return fmt.Errorf("invalid plugin WebSocket status")
}
case PluginServiceSSE:
if status != 200 && status != 500 {
return fmt.Errorf("invalid plugin SSE status")
}
}
return nil
}
func (b *Bundle) validatePluginServiceHTTPResponse(endpoint EndpointSchema, status int, contentType string, payload []byte) error {
if status < 100 || status > 999 {
return fmt.Errorf("invalid plugin service HTTP status")
}
if endpoint.Method == "HEAD" || status < 200 || status == 204 || status == 304 {
if len(payload) > 0 {
return fmt.Errorf("plugin service response forbids a body")
}
return nil
}
// 原始文件、代理及插件自选媒体允许任意字节,具体分支由 ValidatePluginServiceResponse 校验。
return nil
}View on GitHub (pinned to 9f775e8a12)