{"record":{"id":"df3760d64c8d4678","repo":"siyuan-note/siyuan","slug":"invalid-raw-sse-event-declaration","errorCode":null,"errorMessage":"invalid raw SSE event declaration","messagePattern":"invalid raw SSE event declaration","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/apicontract/broadcast_protocol.go","lineNumber":32,"sourceCode":"}\n\ntype RawWebSocketDefinition struct {\n\tFrames               []int `json:\"frames\"`\n\tUpgradeErrorStatuses []int `json:\"upgradeErrorStatuses\"`\n\tEmptyClosedResponse  bool  `json:\"emptyClosedResponse\"`\n}\n\nfunc RawSSEOptions() ResponseOptions {\n\treturn ResponseOptions{Output: SSEOutput, SSE: &SSEDefinition{Raw: &RawSSEDefinition{EventNames: \"dynamic\", DataEncoding: \"raw\", ID: true, Retry: true}}}\n}\n\nfunc RawWebSocketOptions() ResponseOptions {\n\treturn ResponseOptions{Output: WebSocketOutput, WebSocket: &WebSocketDefinition{Raw: &RawWebSocketDefinition{Frames: []int{1, 2, 8, 9, 10}, UpgradeErrorStatuses: []int{400, 403, 405, 500}, EmptyClosedResponse: true}}}\n}\n\nfunc rawSSESchema(definition *SSEDefinition) (*SSESchema, error) {\n\tif len(definition.Events) != 0 || !reflect.DeepEqual(definition.Raw, RawSSEOptions().SSE.Raw) {\n\t\treturn nil, fmt.Errorf(\"invalid raw SSE event declaration\")\n\t}\n\treturn &SSESchema{Raw: definition.Raw}, nil\n}\n\nfunc rawWebSocketSchema(definition *WebSocketDefinition) (*WebSocketSchema, error) {\n\tif definition.Incoming != nil || definition.Outgoing != nil || definition.FailureStatus != 0 || !reflect.DeepEqual(definition.Raw, RawWebSocketOptions().WebSocket.Raw) {\n\t\treturn nil, fmt.Errorf(\"invalid raw WebSocket declaration\")\n\t}\n\treturn &WebSocketSchema{Incoming: &Schema{Type: \"string\", Format: \"binary\"}, Outgoing: &Schema{Type: \"string\", Format: \"binary\"}, Raw: definition.Raw}, nil\n}\n\nfunc validateRawWebSocketHTTP(schema *WebSocketSchema, status int, contentType string, payload []byte) (bool, error) {\n\tif schema.Raw == nil {\n\t\treturn false, nil\n\t}\n\tif status == 101 {\n\t\tif len(payload) != 0 {\n\t\t\treturn true, fmt.Errorf(\"WebSocket upgrade cannot contain a body\")","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/apicontract/broadcast_protocol.go#L14-L50","documentation":"rawSSESchema validates that an endpoint's SSE declaration is exactly the canonical raw-SSE configuration: no named events declared, and the Raw definition deep-equals the RawSSEOptions() baseline. Any deviation — declaring events alongside a raw declaration, or customizing raw fields — is rejected as an invalid declaration. This keeps raw SSE an all-or-nothing mode so the generated schema and runtime validation agree.","triggerScenarios":"BuildBundle (or the test) encounters an SSE definition with a non-empty Events list while Raw is set, or a Raw definition that differs in any field from RawSSEOptions().SSE.Raw (e.g. custom retry, comment, or event-name fields).","commonSituations":"Copy-pasting an evented SSE definition and toggling raw on without clearing Events; hand-editing the raw defaults; mixing old and new schema versions after an upgrade changed the raw baseline.","solutions":["Remove all entries from definition.Events when using raw SSE mode","Use the exact defaults from RawSSEOptions() instead of customizing the Raw struct","Declare either named events (evented mode) or raw mode, never both","Regenerate the contract definition with the current library version"],"exampleFix":"// before\nSSE: &SSEDefinition{Raw: RawSSEOptions().SSE.Raw, Events: []string{\"progress\"}}\n// after\nSSE: &SSEDefinition{Raw: RawSSEOptions().SSE.Raw}","handlingStrategy":"validation","validationCode":"if (def.events?.length) throw new Error(\"raw SSE cannot declare events\");\nif (!deepEqual(def.raw, RawSSEOptions().SSE.Raw)) throw new Error(\"raw SSE definition customized\");","typeGuard":"function isRawSSEDef(d) { return !!d?.raw && (!d.events || d.events.length === 0); }","tryCatchPattern":"try { schema = buildSSE(def); } catch (e) { if (String(e).includes(\"invalid raw SSE event declaration\")) { def = { raw: RawSSEOptions().SSE.Raw }; schema = buildSSE(def); } else throw e; }","preventionTips":["Never mix Events with a Raw SSE declaration","Copy raw defaults from RawSSEOptions() instead of hand-writing them","Regenerate contracts after library upgrades","Add a contract test mirroring TestRawBroadcastProtocols"],"tags":["api-contract","sse","validation"],"backgroundTag":"invalid-config-value","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"}