{"record":{"id":"1e812851f845bd78","repo":"siyuan-note/siyuan","slug":"endpoint-does-not-declare-raw-websocket-frames","errorCode":null,"errorMessage":"endpoint does not declare raw WebSocket frames","messagePattern":"endpoint does not declare raw WebSocket frames","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/apicontract/broadcast_protocol.go","lineNumber":83,"sourceCode":"\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}\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"undeclared raw WebSocket frame: %d\", frameType)\n\t\t}\n\t}\n\treturn fmt.Errorf(\"unregistered API contract: %s %s\", method, path)\n}\n","sourceCodeStart":65,"sourceCodeEnd":98,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/apicontract/broadcast_protocol.go#L65-L98","documentation":"ValidateRawWebSocketFrame finds the endpoint by method+path and requires its WebSocket definition to have Raw mode enabled. If the endpoint is a typed (non-raw) WebSocket or has no WebSocket definition, this error is returned before frame-type checking. It guards against validating raw frames against endpoints with typed message schemas.","triggerScenarios":"Calling bundle.ValidateRawWebSocketFrame for an endpoint whose contract sets Incoming/Outgoing schemas but no Raw definition, or that has no WebSocket contract at all.","commonSituations":"Server migrated a WebSocket endpoint to typed messages while the raw-frame validator client remained; wrong method/path matching a non-WebSocket endpoint; contract definitions out of sync with runtime.","solutions":["Declare the endpoint with RawWebSocketOptions().WebSocket in the contract","Confirm the method and path match the raw WebSocket endpoint exactly","Use the typed WebSocket validation path if the endpoint declares Incoming/Outgoing schemas","Rebuild the bundle after contract changes"],"exampleFix":"// before\n// endpoint declared with Incoming/Outgoing schemas only\nbundle.ValidateRawWebSocketFrame(\"GET\", \"/ws\", true, 1, payload)\n// after\nWebSocket: RawWebSocketOptions().WebSocket\nbundle.ValidateRawWebSocketFrame(\"GET\", \"/ws\", true, 1, 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.WebSocket?.Raw) throw new Error(\"endpoint is not raw WebSocket\");","typeGuard":"function isRawWSEndpoint(ep) { return !!ep?.WebSocket?.Raw; }","tryCatchPattern":"try { bundle.ValidateRawWebSocketFrame(method, path, incoming, frameType, payload); } catch (e) { if (String(e).includes(\"does not declare raw WebSocket frames\")) useTypedFrameValidation(); else throw e; }","preventionTips":["Only call raw frame validation on endpoints declared via RawWebSocketOptions()","Keep raw and typed WebSocket endpoints on distinct paths","Verify method/path against the bundle before validation","Test both raw and typed endpoints after contract changes"],"tags":["api-contract","websocket","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"}