Skip to content
PR Quorum
Sign inStart free
← Review gallery
fastapi/fastapi #15965openreviewed 6h ago

perf: optimize jsonable_encoder by skipping redundant recursive calls…

by rajat315315+191 04 filesreviewed in 1m 47sView PR on GitHub
needs attentionThe panel surfaced issues that deserve attention before merge.3 findings · 2 high+

Reviewer panel

Correctness
deepseek/deepseek-v4-flash
1 found
Security
deepseek/deepseek-v4-flash
0 found
Architecture
deepseek/deepseek-v4-flash
2 found

Findings

01Hhighconf 95%

Short-circuit skips exclude_none/exclude_defaults filtering for nested BaseModel fields

fastapi/encoders.py:244

The new short-circuit path (line 244) returns obj_dict directly when exclude_none and exclude_defaults are both falsy. However, model_dump(mode="json") only filters top-level fields according to these parameters — it does NOT recursively strip None values or default values from nested dicts/lists. The original recursive jsonable_encoder did perform that deep cleanup. This means that for a model with nested models, exclude_none=True or exclude_defaults=True will now skip the short-circuit (falling through to the old recursive path), but the old path still calls model_dump with those parameters, which only filters top-level. The nested cleanup is lost.

02Hhighconf 90%

sqlalchemy_safe filtering not applied to nested dicts in short-circuit path

fastapi/encoders.py:248

The early return for BaseModel (lines 248-255) returns obj_dict directly after filtering only the top-level keys for _sa prefixes. The old code recursively called jsonable_encoder on the dict, which applied sqlalchemy_safe filtering to all nested dicts. This change means that when sqlalchemy_safe=True (the default) and neither exclude_none nor exclude_defaults is set, nested dicts inside the model (e.g., a field of type dict that contains _sa keys) will not have those keys removed. This is a behavioral regression that could leak SQLAlchemy internal attributes in serialized output.

03Llowconf 90%

Unnecessary conditional short-circuit adds complexity

fastapi/encoders.py:241

The condition if not exclude_none and not exclude_defaults: gates the short-circuit path, but model_dump(mode="json") already handles exclude_none, exclude_defaults, and all other exclude parameters correctly. The fallback path (when either flag is True) duplicates the model_dump call and the sqlalchemy_safe filtering, and then performs a redundant recursive jsonable_encoder call that does nothing useful because the dict is already fully serialized. This adds unnecessary code duplication and cognitive overhead. The short-circuit could be applied unconditionally, and the sqlalchemy_safe filtering could be handled by a separate recursive helper if needed (see the high-severity finding about nested dicts).

Want this on your own pull requests?
The same reviewer panel runs on every PR — one focused review, no noise.
Start freeLive demo