Spaces:
Running
FixFlow Sample Output β FastAPI Bug Analysis
Issue: FastAPI response_model doesn't strip extra fields when using Pydantic v2
Repository: https://github.com/tiangolo/fastapi
Analysis Time: 87.3s
π Step 1: Bug Summary
π Error Message
"When using
response_modelin FastAPI with Pydantic v2, extra fields defined in the response model are NOT stripped from the response. This breaks the behavior expected from theresponse_model_exclude_unsetpattern."
β Expected Behavior
When a route has a response_model set, FastAPI should filter the response to only include fields defined in that model, stripping any additional fields from the underlying return value.
β Actual Behavior
Extra fields from the returned object are included in the JSON response even when a response_model is specified. This is a regression from Pydantic v1 behavior.
π Reproduction Steps
- Install
fastapi>=0.100.0withpydantic>=2.0.0 - Define a route:
@app.get("/users/{id}", response_model=UserOut) - Return a
UserDBobject with extra fields not inUserOut - Observe: response includes the extra fields
π― Affected Components
fastapi/routing.pyβ route handler serialization logicfastapi/_compat.pyβ Pydantic v1/v2 compatibility layerfastapi/encoders.pyβ JSON encoding pipeline
π Key Technical Clues
- Introduced after Pydantic v2 migration
_get_value()infastapi/_compat.pychanged behavior for model instances- The
model_dump(exclude_unset=True)call may not be filtering correctly
π‘ Hypothesis
The Pydantic v2 compatibility layer in _compat.py is not correctly calling model_dump() with the include/exclude parameters that respect the response_model field constraints. The v2 migration changed how model field serialization works.
π Step 2: Relevant Files
π Relevant Files (Ranked by Suspicion)
1. fastapi/_compat.py
- Relevance score: 10/10
- Why relevant: This is the Pydantic v1/v2 compatibility shim. All serialization changes went through here during the v2 migration.
- What to look for:
_get_value(),serialize_response(), any calls tomodel_dump()
2. fastapi/routing.py
- Relevance score: 9/10
- Why relevant: Contains
serialize_response()calls that applyresponse_modelfiltering. - What to look for:
get_request_handler(), howresponse_model_includeandresponse_model_excludeare passed.
3. fastapi/encoders.py
- Relevance score: 7/10
- Why relevant:
jsonable_encoder()handles the final conversion to JSON-safe types. - What to look for: Whether
include/excludesets are respected for Pydantic v2 models.
π¬ Step 3: Root Cause Analysis
Executive Summary
In fastapi/_compat.py, the _get_value() function for Pydantic v2 models calls model_dump() without passing the include parameter derived from the response_model's field set, causing all fields to be serialized instead of only those defined in the response model.
π§ Chain-of-Thought Reasoning
Step 1: Entry Point
A GET request hits a route decorated with @app.get("/users/{id}", response_model=UserOut). FastAPI's routing.py:get_request_handler() is invoked, which calls serialize_response().
Step 2: Execution Trace
routing.py:serialize_response()β calls_compat.py:serialize_response()withresponse_model=UserOut_compat.py:serialize_response()calls_get_value(response, field=response_model_field, ...)- Here's the bug: For Pydantic v2,
_get_value()callsvalue.model_dump()but does NOT passinclude=field_setwherefield_setcontains only the fields defined inUserOut
Step 3: The Bug
In fastapi/_compat.py, around line 215, the v2 branch of _get_value():
# BUGGY (current):
return value.model_dump(exclude_unset=exclude_unset, by_alias=by_alias)
# Should be:
return value.model_dump(
include=include,
exclude=exclude,
exclude_unset=exclude_unset,
by_alias=by_alias,
)
The include parameter (containing the response_model's allowed fields) is accepted as a function argument but silently dropped in the v2 code path.
Step 4: Why This Causes the Reported Behavior
Without the include parameter, model_dump() serializes ALL fields of the returned object, bypassing the response_model restriction. In Pydantic v1, _get_value() used dict() which was correctly called with include β this broke during the v2 migration.
π Bug Location
- File:
fastapi/_compat.py - Function/Class:
_get_value() - Line(s): ~215
- Type: Missing parameter pass-through (regression from Pydantic v2 migration)
π― Confidence Level
High β The bug is clearly a missing parameter in a well-understood code path. The fix is straightforward and surgical.
π§ Step 4: Proposed Fix
--- a/fastapi/_compat.py
+++ b/fastapi/_compat.py
@@ -212,7 +212,11 @@ def _get_value(
if PYDANTIC_V2:
if isinstance(value, BaseModel):
- return value.model_dump(exclude_unset=exclude_unset, by_alias=by_alias)
+ # Pass include/exclude to respect response_model field constraints
+ # This was missing after the Pydantic v2 migration (regression fix)
+ return value.model_dump(
+ include=include,
+ exclude=exclude,
+ exclude_unset=exclude_unset,
+ by_alias=by_alias,
+ )
π Step 5: PR Description
π Pull Request: Fix response_model field filtering with Pydantic v2
π Problem
When using FastAPI with Pydantic v2, the response_model parameter on route decorators no longer strips extra fields from responses. A route returning a UserDB object (with password, internal fields) but declaring response_model=UserOut would incorrectly expose the extra fields to clients.
π Root Cause
During the Pydantic v2 migration, fastapi/_compat.py's _get_value() function lost the include parameter pass-through in the v2 code path. The model_dump() call was not forwarding the field inclusion constraints derived from the response_model.
π§ Solution
Added include=include and exclude=exclude parameters to the model_dump() call in the Pydantic v2 branch of _get_value(). This restores the Pydantic v1 behavior where only response_model fields are serialized.
π§ͺ Testing Recommendations
- Create a route returning an object with extra fields, verify response only includes
response_modelfields - Test
response_model_exclude_unset=Truestill works correctly - Run existing test suite:
pytest tests/test_response_model.py -v
β οΈ Potential Side Effects
None identified. Change only affects the Pydantic v2 code path and is additive β it passes parameters that were already being constructed but not forwarded.
Generated by FixFlow β Autonomous Bug Resolution Agent powered by GLM 5.1 (Z.ai)