siyuan-note/siyuan · error

invalid plugin service HTTP status

Error message

invalid plugin service HTTP status: %d

What it means

validatePluginServiceStatus checks that a plugin service response status is a valid HTTP code (100-999) and also that it is permitted for the selected PluginServiceMode. This specific error fires when the status integer falls outside 100-999 (zero or negative values already normalized to 200 by StreamPluginService, so this typically comes from a raw, unvalidated status). Callers include StreamPluginService (panics), pluginServiceStatus, and ValidatePluginServiceResponse.

Solutions

  1. Pass a valid HTTP status (100-999) to StreamPluginService; omit it (or pass <= 0) to get the 200 default
  2. Clamp or validate computed status values before constructing the response
  3. Check upstream proxies/forwarded codes and map anything outside 100-999 to a standard status

Example fix

// before
status := baseStatus + delta*1000
resp := apicontract.StreamPluginService(apicontract.PluginServiceJSON, status, serve)
// after
if status < 100 || status > 999 {
    status = http.StatusInternalServerError
}
resp := apicontract.StreamPluginService(apicontract.PluginServiceJSON, status, serve)
Defensive patterns

Strategy: validation

Validate before calling

func validStatus(s int) bool { return s >= 100 && s <= 999 }
if !validStatus(status) { status = http.StatusInternalServerError }

Try / catch

func serve(mode apicontract.PluginServiceMode, status int) (r apicontract.Response[apicontract.PluginServiceContent]) {
    defer func() { if rec := recover(); rec != nil { log.Printf("status rejected: %v", rec); r = fallback(mode) } }()
    return apicontract.StreamPluginService(mode, status, handler)
}

Prevention

When it happens

Trigger: StreamPluginService(mode, status, serve) is called with a status < 100 or > 999; a Response[PluginServiceContent] carries an out-of-range httpStatus when the endpoint computes pluginServiceStatus; ValidatePluginServiceResponse is invoked with a bad status during bundle response validation.

Common situations: Passing an error-sentinel status like -1 or 0 from application code that assumed the library would substitute a default (only 0/negative is normalized, but custom paths may bypass), computing a status arithmetically (e.g. 200+extra*1000), or forwarding an upstream status code larger than 999.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/1fe23e789a2b3f9e. Report an issue: GitHub.

Appendix: source

Thrown at kernel/apicontract/plugin_service_protocol.go:135

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
		}
	}
	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) {

View on GitHub (pinned to 9f775e8a12)