{"id":"aeae7ed34e07c0af","repo":"tiangolo/fastapi","slug":"sse-field-name-must-be-a-single-line","errorCode":null,"errorMessage":"SSE '{field_name}' must be a single line","messagePattern":"SSE '(.+?)' must be a single line","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"fastapi/sse.py","lineNumber":38,"sourceCode":"class EventSourceResponse(StreamingResponse):\n    \"\"\"Streaming response with `text/event-stream` media type.\n\n    Use as `response_class=EventSourceResponse` on a *path operation* that uses `yield`\n    to enable Server Sent Events (SSE) responses.\n\n    Works with **any HTTP method** (`GET`, `POST`, etc.), which makes it compatible\n    with protocols like MCP that stream SSE over `POST`.\n\n    The actual encoding logic lives in the FastAPI routing layer. This class\n    serves mainly as a marker and sets the correct `Content-Type`.\n    \"\"\"\n\n    media_type = \"text/event-stream\"\n\n\ndef _check_single_line(v: str | None, field_name: str) -> str | None:\n    if v is not None and (\"\\r\" in v or \"\\n\" in v):\n        raise ValueError(f\"SSE '{field_name}' must be a single line\")\n    return v\n\n\ndef _check_event_single_line(v: str | None) -> str | None:\n    return _check_single_line(v, \"event\")\n\n\ndef _check_id_valid(v: str | None) -> str | None:\n    if v is not None and \"\\0\" in v:\n        raise ValueError(\"SSE 'id' must not contain null characters\")\n    return _check_single_line(v, \"id\")\n\n\nclass ServerSentEvent(BaseModel):\n    \"\"\"Represents a single Server-Sent Event.\n\n    When `yield`ed from a *path operation function* that uses\n    `response_class=EventSourceResponse`, each `ServerSentEvent` is encoded","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/tiangolo/fastapi/blob/42a41db11f6882807ac3c057b942178d53b97438/fastapi/sse.py#L20-L56","documentation":"`ServerSentEvent` applies `AfterValidator(_check_single_line)` (sse.py:36-39, 97-122) to the `event` and `id` fields. If the value contains `\\r` or `\\n`, pydantic raises `ValueError`, which surfaces as a validation error when the event is constructed. SSE wire format encodes each field on a single line; embedded line breaks would corrupt the stream framing.","triggerScenarios":"Yielding `ServerSentEvent(event=\"user\\nupdate\", data=...)` or `ServerSentEvent(id=\"a\\rb\", data=...)` from an `EventSourceResponse` path operation. Passing user/DB text into `event` or `id` that happens to contain a newline.","commonSituations":"Using a free-form string (log line, message body, slug with a trailing newline) as an event name; reading `id` from a source that includes a line break; Windows text containing `\\r\\n`.","solutions":["Strip/replace line breaks before assigning: `event=name.replace(\"\\r\", \" \").replace(\"\\n\", \" \")`.","Restrict `event`/`id` to slugs/identifiers you control, not arbitrary text.","Put multi-line content in `data`/`raw_data` instead, which is allowed to span lines.","Add a unit test that constructs your events with the longest/edgiest inputs."],"exampleFix":"# before\nyield ServerSentEvent(event=\"user\\nupdate\", data=payload)\n\n# after\nevent_name = \"user_update\"  # sanitize / slugify\nyield ServerSentEvent(event=event_name, data=payload)","handlingStrategy":"validation","validationCode":"def sse_single_line(value: str | None, field: str = \"value\") -> str | None:\n    if value is not None and (\"\\r\" in value or \"\\n\" in value):\n        raise ValueError(f\"{field} must be a single line: {value!r}\")\n    return value\n\ndef sanitize_sse_field(value: str | None) -> str | None:\n    if value is None:\n        return None\n    return value.replace(\"\\r\\n\", \" \").replace(\"\\r\", \" \").replace(\"\\n\", \" \")\n\n# usage\nevt = sanitize_sse_field(user_event_name)\nyield ServerSentEvent(event=evt, data=payload)","typeGuard":"def is_single_line(value: str | None) -> bool:\n    return value is None or (\"\\r\" not in value and \"\\n\" not in value)","tryCatchPattern":"from fastapi.sse import ServerSentEvent\n\ntry:\n    yield ServerSentEvent(event=name, data=payload)\nexcept ValueError as exc:  # pydantic validation on construction\n    logging.warning(\"dropping malformed SSE event: %s\", exc)\n    yield ServerSentEvent(event=\"message\", data=payload)  # safe fallback","preventionTips":["Treat `event` and `id` as identifiers/slugs, never free-form text.","Sanitize any external value used for these fields before constructing the event.","Put multi-line payloads in `data`/`raw_data`, which permits line breaks."],"tags":["sse","server-sent-events","validation"],"analyzedSha":"42a41db11f6882807ac3c057b942178d53b97438","analyzedAt":"2026-08-04T19:23:32.007Z","schemaVersion":2}