🐛 Fix response model serialization options for SSE event data by kagami-tsukimura · Pull Request #15708 · fastapi/fastapi · GitHub
Skip to content

🐛 Fix response model serialization options for SSE event data#15708

Open
kagami-tsukimura wants to merge 3 commits into
fastapi:masterfrom
kagami-tsukimura:fix-sse-event-data-serialization-options
Open

🐛 Fix response model serialization options for SSE event data#15708
kagami-tsukimura wants to merge 3 commits into
fastapi:masterfrom
kagami-tsukimura:fix-sse-event-data-serialization-options

Conversation

@kagami-tsukimura

Copy link
Copy Markdown

Pull Request

🐛 Fix response model serialization options for SSE event data

Discussion: #15703

Description

This fixes the ServerSentEvent(data=...) serialization path for Pydantic models.

Previously, this path called model_dump_json() without forwarding the route's response model serialization options. Because of that, models used as SSE event data could ignore options such as response_model_by_alias, response_model_include, response_model_exclude, response_model_exclude_none, response_model_exclude_unset, and response_model_exclude_defaults.

This now passes those options to model_dump_json(), matching the behavior used by regular streamed response items.

I added regression tests for serialization aliases, response_model_by_alias=False, response_model_include, response_model_exclude, response_model_exclude_none, response_model_exclude_unset, and response_model_exclude_defaults.

I ran locally:

uv run pytest -q tests/test_sse.py
uv run pytest -q tests/test_sse.py tests/test_response_by_alias.py tests/test_response_model_include_exclude.py tests/test_serialize_response_model.py
uv run ruff check fastapi/routing.py tests/test_sse.py
git diff --check

AI Disclaimer

I used Codex as a coding assistant while preparing this PR.

After identifying the missing by_alias handling and confirming it in the discussion, I used Codex to inspect the same ServerSentEvent(data=...) serialization path for other response model serialization options.

Codex helped me check for similar missing options, draft the focused regression tests, run local checks, and prepare this PR description. I reviewed the code changes, the test coverage, and the command results before opening the PR.

AI transcript

The code-related AI assistance was:

User:

I identified that ServerSentEvent(data=...) does not respect by_alias when
the data is a Pydantic model, and confirmed it in the discussion. Before opening
a PR, check whether the same path misses any other response model serialization
options.

Codex:

I will inspect the SSE serialization path and compare it with the regular
streamed response model serialization path.

In fastapi/routing.py, plain streamed items use:

stream_item_field.serialize_json(
    value,
    include=response_model_include,
    exclude=response_model_exclude,
    by_alias=response_model_by_alias,
    exclude_unset=response_model_exclude_unset,
    exclude_defaults=response_model_exclude_defaults,
    exclude_none=response_model_exclude_none,
)

But ServerSentEvent(data=...) with a Pydantic model calls:

item.data.model_dump_json()

So the same path is not only missing by_alias; it is also missing the route's
include, exclude, exclude_unset, exclude_defaults, and exclude_none
serialization options.

User:

Update the fix so it handles the missing response model serialization options,
and add regression tests for the changed behavior.

Codex:

I updated the model_dump_json() call to pass the route serialization options:

item.data.model_dump_json(
    include=response_model_include,
    exclude=response_model_exclude,
    by_alias=response_model_by_alias,
    exclude_unset=response_model_exclude_unset,
    exclude_defaults=response_model_exclude_defaults,
    exclude_none=response_model_exclude_none,
)

I also added focused SSE regression tests for:

  • serialization aliases
  • response_model_by_alias=False
  • response_model_include
  • response_model_exclude
  • response_model_exclude_none
  • response_model_exclude_unset
  • response_model_exclude_defaults

User:

Run the focused checks.

Codex:

The focused checks passed:

uv run pytest -q tests/test_sse.py
uv run pytest -q tests/test_sse.py tests/test_response_by_alias.py tests/test_response_model_include_exclude.py tests/test_serialize_response_model.py
uv run ruff check fastapi/routing.py tests/test_sse.py
git diff --check

Checklist

  • This PR is an obvious typo fix, or it links to a GitHub Discussion for the proposed code change.
  • I added tests for the change.
  • The new or updated tests fail on the main branch and pass on this PR.
  • Coverage stays at 100%.
  • The documentation explains the change if needed.

@codspeed-hq

codspeed-hq Bot commented Jun 8, 2026

Copy link
Copy Markdown

@avinashkamat48 avinashkamat48 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This applies the response-model serialization options only when ServerSentEvent.data is a Pydantic model with model_dump_json. The fallback branch still calls jsonable_encoder(item.data) without include, exclude, by_alias, or the exclude flags, so dicts/dataclasses/lists of models sent as event data will continue ignoring the route's response serialization options. Please either pass the same options through jsonable_encoder in the fallback path or add a test that documents the limitation.

@kagami-tsukimura

Copy link
Copy Markdown
Author

@svlandeg svlandeg added the bug Something isn't working label Jun 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants