@@ -428,21 +428,28 @@ def ser_model(
428428 if (ctx := info .context ) and ctx .get ("include_secrets" ) is True :
429429 # Add serialization mode to context so handle_secret_render knows how to process nested models
430430 ctx ["serialization_mode" ] = info .mode
431+ ctx ["by_alias" ] = info .by_alias
431432
432- for field_name in type (self ).model_fields :
433+ for field_name , field_info in type (self ).model_fields . items () :
433434 field_value = getattr (self , field_name )
434435
435- # In JSON mode, skip fields that don't contain secrets
436+ # Determine the correct key in the serialized dict,
437+ # respecting alias settings to avoid creating duplicate
438+ # entries (e.g. both "schema" and "schema_" for a field
439+ # defined as `schema_: str = Field(alias="schema")`).
440+ alias = field_info .serialization_alias or field_info .alias
441+ if info .by_alias and alias :
442+ key = alias
443+ else :
444+ key = field_name
445+
446+ # Skip fields that don't contain secrets
436447 # as they're already properly serialized by the handler
437- if (
438- info .mode == "json"
439- and field_name in jsonable_self
440- and not self ._field_has_secrets (field_name )
441- ):
448+ if key in jsonable_self and not self ._field_has_secrets (field_name ):
442449 continue
443450
444451 # For all other fields, use visit_collection with handle_secret_render
445- jsonable_self [field_name ] = visit_collection (
452+ jsonable_self [key ] = visit_collection (
446453 expr = field_value ,
447454 visit_fn = partial (handle_secret_render , context = ctx ),
448455 return_data = True ,
0 commit comments