siyuan-note/siyuan · error
invalid plugin redirect status
Error message
invalid plugin redirect status
What it means
Redirect-mode plugin service responses must use 201 or a 3xx status in the 300-308 range; validatePluginServiceStatus rejects any other status. The kernel enforces this so redirect responses in the contract always correspond to real HTTP redirect semantics.
Solutions
- Use a valid redirect status: 301, 302, 303, 304 (where applicable), 307, 308, or 201
- Use 201 only when the redirect also represents resource creation semantics
- If the response is not a redirect, switch the variant (e.g. PluginServiceJSON with status 200)
Example fix
// before StreamPluginService(PluginServiceRedirect, 200, serve) // after StreamPluginService(PluginServiceRedirect, http.StatusFound, serve) // 302
Defensive patterns
Strategy: validation
Validate before calling
func validRedirectStatus(status int) bool {
return status == 201 || (status >= 300 && status <= 308)
} Try / catch
defer func() {
if rec := recover(); rec != nil {
log.Printf("invalid redirect status: %v", rec)
}
}() // around StreamPluginService(PluginServiceRedirect, ...) Prevention
- Use net/http constants (StatusMovedPermanently, StatusFound, StatusSeeOther, StatusTemporaryRedirect, StatusPermanentRedirect)
- Never reuse a 200-OK helper for redirect responses
- Add table tests covering each redirect status you emit
When it happens
Trigger: Calling StreamPluginService(PluginServiceRedirect, status, serve) or ValidatePluginServiceResponse with redirect mode and a status like 200, 400, or 309 (outside 300-308 and not 201).
Common situations: Returning a normal success page (200) through redirect mode; using 301/308 with a non-GET method assumption error; hand-picking an unusual code such as 310 that was removed from the HTTP spec.
Related errors
- invalid plugin SSE 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/d9c0dbe6fe4e691d.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/apicontract/plugin_service_protocol.go:154
}
known := false
for _, variant := range PluginServiceOptions().PluginService.Variants {
if variant.Mode == mode {
known = true
break
}
}
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 {View on GitHub (pinned to 9f775e8a12)