{"id":"0aa9b7ff7955b8f0","repo":"tiangolo/fastapi","slug":"cannot-set-both-data-and-raw-data-on-the-same","errorCode":null,"errorMessage":"Cannot set both 'data' and 'raw_data' on the same ServerSentEvent. Use 'data' for JSON-serialized payloads or 'raw_data' for pre-formatted strings.","messagePattern":"Cannot set both 'data' and 'raw_data' on the same ServerSentEvent\\. Use 'data' for JSON-serialized payloads or 'raw_data' for pre-formatted strings\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"fastapi/sse.py","lineNumber":151,"sourceCode":"        ),\n    ] = None\n    comment: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            Optional comment line(s).\n\n            Comment lines start with `:` in the SSE wire format and are ignored by\n            `EventSource` clients. Useful for keep-alive pings to prevent\n            proxy/load-balancer timeouts.\n            \"\"\"\n        ),\n    ] = None\n\n    @model_validator(mode=\"after\")\n    def _check_data_exclusive(self) -> \"ServerSentEvent\":\n        if self.data is not None and self.raw_data is not None:\n            raise ValueError(\n                \"Cannot set both 'data' and 'raw_data' on the same \"\n                \"ServerSentEvent. Use 'data' for JSON-serialized payloads \"\n                \"or 'raw_data' for pre-formatted strings.\"\n            )\n        return self\n\n\ndef _split_sse_lines(value: str) -> list[str]:\n    # Split on SSE-spec line terminators only (\\n, \\r\\n, \\r), preserving\n    # trailing empty strings.\n    return value.replace(\"\\r\\n\", \"\\n\").replace(\"\\r\", \"\\n\").split(\"\\n\")\n\n\ndef format_sse_event(\n    *,\n    data_str: Annotated[\n        str | None,\n        Doc(","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/tiangolo/fastapi/blob/42a41db11f6882807ac3c057b942178d53b97438/fastapi/sse.py#L133-L169","documentation":"`ServerSentEvent` has a pydantic `model_validator(mode=\"after\")`, `_check_data_exclusive` (sse.py:148-156), that raises `ValueError` if both `data` and `raw_data` are set (both not None). `data` is JSON-serialized; `raw_data` is sent verbatim. They are mutually exclusive because the encoder must pick one serialization strategy.","triggerScenarios":"Constructing `ServerSentEvent(data={\"x\": 1}, raw_data=\"custom\")`, or `ServerSentEvent(data=\"txt\", raw_data=\"other\")`. Often happens when forwarding an existing dict into `data` while a default `raw_data` is also supplied, or vice versa.","commonSituations":"Branching code that sometimes sets `data` and sometimes `raw_data` but doesn't clear the other; spreading defaults via `{**base, \"data\": ...}` while `raw_data` is already in `base`; refactoring from one field to the other and leaving both populated.","solutions":["Set exactly one of `data` or `raw_data` per event.","When building events programmatically, pop the unused key: `evt = {\"raw_data\": text}; evt.pop(\"data\", None)`.","Use `data` for JSON payloads (dicts, models, even strings get quoted) and `raw_data` only for pre-formatted non-JSON text."],"exampleFix":"# before\nyield ServerSentEvent(data={\"x\": 1}, raw_data=\"custom\")\n\n# after\nyield ServerSentEvent(raw_data=\"custom\")\n# or, for JSON:\nyield ServerSentEvent(data={\"x\": 1})","handlingStrategy":"type-guard","validationCode":"from typing import Any\nfrom fastapi.sse import ServerSentEvent\n\ndef make_event(*, data: Any = None, raw_data: str | None = None, **kw):\n    if data is not None and raw_data is not None:\n        raise ValueError(\"set only one of data or raw_data\")\n    return ServerSentEvent(data=data, raw_data=raw_data, **kw)","typeGuard":"def is_exclusive_payload(data, raw_data) -> bool:\n    return (data is None) or (raw_data is None)","tryCatchPattern":"from fastapi.sse import ServerSentEvent\n\ntry:\n    yield ServerSentEvent(data=d, raw_data=rd, event=\"e\")\nexcept ValueError as exc:\n    # pick a deterministic fallback strategy\n    payload = rd if rd is not None else d\n    if isinstance(payload, str):\n        yield ServerSentEvent(raw_data=payload, event=\"e\")\n    else:\n        yield ServerSentEvent(data=payload, event=\"e\")","preventionTips":["Build SSE events through a small factory that enforces exclusivity.","When spreading defaults, pop the unused key explicitly.","Use `raw_data` only for pre-formatted non-JSON text; otherwise prefer `data`."],"tags":["sse","server-sent-events","validation"],"analyzedSha":"42a41db11f6882807ac3c057b942178d53b97438","analyzedAt":"2026-08-04T19:23:32.007Z","schemaVersion":2}