{"record":{"id":"131fadaf6663c157","repo":"siyuan-note/siyuan","slug":"endpoint-does-not-declare-raw-sse-events","errorCode":null,"errorMessage":"endpoint does not declare raw SSE events","messagePattern":"endpoint does not declare raw SSE events","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/apicontract/broadcast_protocol.go","lineNumber":71,"sourceCode":"\t}\n\tif status == 200 && len(payload) == 0 && schema.Raw.EmptyClosedResponse {\n\t\treturn true, nil\n\t}\n\tmedia, _, _ := mime.ParseMediaType(contentType)\n\tfor _, allowed := range schema.Raw.UpgradeErrorStatuses {\n\t\tif status == allowed && media == \"text/plain\" {\n\t\t\treturn true, nil\n\t\t}\n\t}\n\treturn false, nil\n}\n\n// ValidateRawSSEEvent 校验事件协议；事件数据是原始字节，不进行 JSON 解码或 Base64 转码。\nfunc (b *Bundle) ValidateRawSSEEvent(method, path, name, id string, retry uint, payload []byte) error {\n\tfor _, endpoint := range b.Endpoints {\n\t\tif endpoint.Method == method && endpoint.Path == path {\n\t\t\tif endpoint.SSE == nil || endpoint.SSE.Raw == nil {\n\t\t\t\treturn fmt.Errorf(\"endpoint does not declare raw SSE events\")\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\t}\n\treturn fmt.Errorf(\"unregistered API contract: %s %s\", method, path)\n}\n\nfunc (b *Bundle) ValidateRawWebSocketFrame(method, path string, incoming bool, frameType int, payload []byte) error {\n\tfor _, endpoint := range b.Endpoints {\n\t\tif endpoint.Method == method && endpoint.Path == path {\n\t\t\tif endpoint.WebSocket == nil || endpoint.WebSocket.Raw == nil {\n\t\t\t\treturn fmt.Errorf(\"endpoint does not declare raw WebSocket frames\")\n\t\t\t}\n\t\t\tfor _, allowed := range endpoint.WebSocket.Raw.Frames {\n\t\t\t\tif frameType == allowed {\n\t\t\t\t\tif frameType >= 8 && len(payload) > 125 {\n\t\t\t\t\t\treturn fmt.Errorf(\"WebSocket control frame exceeds 125 bytes\")\n\t\t\t\t\t}","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/apicontract/broadcast_protocol.go#L53-L89","documentation":"ValidateRawSSEEvent looks up the endpoint by method+path in the bundle and requires it to have both an SSE definition and Raw mode enabled. If the endpoint exists but is not declared as raw SSE (or has no SSE at all), this error is returned. It prevents validating raw byte events against an endpoint whose SSE contract is evented or absent.","triggerScenarios":"Calling bundle.ValidateRawSSEEvent(method, path, ...) for an endpoint whose contract declares named SSE events (SSE != nil but Raw == nil) or no SSE definition at all.","commonSituations":"Client code switched from evented to raw SSE (or vice versa) without updating the contract; calling the raw validator with the wrong method/path so it matches a non-SSE endpoint; contract and server code drifted after a refactor.","solutions":["Declare the endpoint with RawSSEOptions() (SSE with Raw set) in the contract","Verify the method and path arguments exactly match the registered endpoint","Update the caller to use the evented SSE validation path if the endpoint is evented","Regenerate/rebuild the bundle so it contains the current endpoint definitions"],"exampleFix":"// before\n// endpoint declared: SSE: &SSEDefinition{Events: events}  (evented)\nbundle.ValidateRawSSEEvent(\"GET\", \"/api/raw\", name, id, retry, payload)\n// after\nSSE: RawSSEOptions().SSE\nbundle.ValidateRawSSEEvent(\"GET\", \"/api/raw\", name, id, retry, payload)","handlingStrategy":"validation","validationCode":"const ep = bundle.Endpoints.find(e => e.Method === method && e.Path === path);\nif (!ep) throw new Error(\"unregistered: \" + method + \" \" + path);\nif (!ep.SSE?.Raw) throw new Error(\"endpoint is not raw SSE\");","typeGuard":"function isRawSSEEndpoint(ep) { return !!ep?.SSE?.Raw; }","tryCatchPattern":"try { bundle.ValidateRawSSEEvent(method, path, name, id, retry, payload); } catch (e) { if (String(e).includes(\"does not declare raw SSE events\")) switchToEventedValidation(); else throw e; }","preventionTips":["Check the endpoint contract before choosing raw vs evented validation","Keep contract declarations and runtime callers in the same module","Match method and path strings exactly to registration","Cover raw/evented routing in tests"],"tags":["api-contract","sse","unregistered-endpoint"],"backgroundTag":"resource-not-found","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}