siyuan-note/siyuan · error

proxy output requires a protocol declaration

Error message

proxy output requires a protocol declaration: %s

What it means

validateProxyDefinition enforces that proxy configuration is all-or-nothing: a Definition must either declare both ProxyOutput and a Proxy protocol, or neither. If one side is set without the other, it returns "proxy output requires a protocol declaration: %s" naming the endpoint. This catches definitions that claim proxy output but lack the HTTP/EventSource/WebSocket proxy spec (or vice versa), which would leave the runtime unable to construct the upstream transport.

Solutions

  1. Set both fields consistently: Output: ProxyOutput together with a non-nil Proxy (HTTPProxy, EventSourceProxy, or WebSocketProxy)
  2. If the endpoint is not a proxy, remove the Proxy declaration instead of leaving it set with a non-proxy Output
  3. Or keep Proxy and add the missing Output: ProxyOutput to the definition
  4. Add a unit test mirroring TestProxyDefinitionRejectsUnknownProtocol so BuildBundle fails fast with the endpoint name

Example fix

// before
Definition{Name: "upstream", Output: ProxyOutput}
// after
Definition{Name: "upstream", Output: ProxyOutput, Proxy: &ProxyDeclaration{Kind: HTTPProxy}}
Defensive patterns

Strategy: validation

Validate before calling

func proxyDeclarationIsConsistent(d Definition) bool { return (d.Output == ProxyOutput) == (d.Proxy != nil) }

Try / catch

if err := BuildBundle(defs); err != nil { if strings.Contains(err.Error(), "proxy output requires a protocol declaration") { logDefectDefinition(err); return }; return err } — better: run validateProxyDefinition-equivalent checks in unit tests before BuildBundle

Prevention

When it happens

Trigger: Building a bundle (BuildBundle) with a Definition whose Output is ProxyOutput but whose Proxy field is nil; or conversely setting Definition.Proxy while leaving Output as a regular JSON output — surfaced by TestProxyDefinitionRejectsUnknownProtocol-style tests and at bundle construction time.

Common situations: A developer adds Output: ProxyOutput but forgets to fill Proxy: &Proxy{Kind: ...}; a refactor switches an endpoint to proxy mode and removes Output but forgets to remove Proxy; copy-pasted definitions partially updated; a code path builds Definitions programmatically and conditionally sets only one of the two fields.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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

Appendix: source

Thrown at kernel/apicontract/proxy_protocol.go:91

			panic("invalid upstream proxy status")
		}
		return response.httpStatus
	}
	if response.directJSON {
		if response.httpStatus != 400 && response.httpStatus != 502 {
			panic("undeclared proxy rejection status")
		}
		return response.httpStatus
	}
	if response.code == 0 {
		panic("proxy response requires a stream or rejection")
	}
	return 200
}

func validateProxyDefinition(definition Definition) error {
	if (definition.Output == ProxyOutput) != (definition.Proxy != nil) {
		return fmt.Errorf("proxy output requires a protocol declaration: %s", definition.Name)
	}
	if definition.Proxy == nil {
		return nil
	}
	if definition.Proxy.Kind != HTTPProxy && definition.Proxy.Kind != EventSourceProxy && definition.Proxy.Kind != WebSocketProxy {
		return fmt.Errorf("unsupported proxy protocol: %s", definition.Proxy.Kind)
	}
	if definition.Data != reflect.TypeFor[ProxyFailure]() || definition.DataOnError || definition.ErrorStatus != 0 || definition.SSE != nil || definition.WebSocket != nil {
		return fmt.Errorf("invalid proxy response options: %s", definition.Name)
	}
	want := ProxyOptions(definition.Proxy.Kind).Proxy
	if !reflect.DeepEqual(want, definition.Proxy) {
		return fmt.Errorf("invalid proxy protocol declaration: %s", definition.Name)
	}
	return nil
}

// validateProxyHTTPResponse 按媒体类型区分上游字节和内核准入失败,同状态不代表同协议。

View on GitHub (pinned to 9f775e8a12)