Skip to main content

Field Mapping and Alias Resolution

Field mapping and alias resolution allow you to decouple the internal names of your fields from the keys used in external data formats like JSON. This is controlled through field-level alias definitions and global configuration settings in CoreConfig.

Mapping Input Data with Validation Aliases

To map an external key to an internal field name during validation, use the validation_alias property. This is available on ModelField, TypedDictField, and DataclassField.

from pydantic_core import SchemaValidator, core_schema

v = SchemaValidator(
core_schema.typed_dict_schema(
fields={
'internal_name': core_schema.typed_dict_field(
schema=core_schema.int_schema(),
validation_alias='external_key'
)
}
)
)

# Validates using the alias
assert v.validate_python({'external_key': 123}) == {'internal_name': 123}

Enabling Validation by Name

By default, if a validation_alias is provided, the validator only looks for that alias. You can enable fallback to the field's internal name by setting validate_by_name=True in the CoreConfig.

from pydantic_core import SchemaValidator, core_schema, CoreConfig

v = SchemaValidator(
core_schema.typed_dict_schema(
fields={
'field_a': core_schema.typed_dict_field(
schema=core_schema.int_schema(),
validation_alias='FieldA'
)
},
config=CoreConfig(validate_by_name=True)
)
)

# Works with alias
assert v.validate_python({'FieldA': 1}) == {'field_a': 1}
# Works with name because validate_by_name=True
assert v.validate_python({'field_a': 1}) == {'field_a': 1}

Advanced Validation Paths

The validation_alias can be more than just a string. It supports complex paths and multiple alternative locations.

Extracting Nested Data

You can provide a list of strings and integers to extract data from nested structures. The first item in the list must be a string (the key in the top-level dictionary).

v = SchemaValidator(
core_schema.typed_dict_schema(
fields={
'user_id': core_schema.typed_dict_field(
# Path: look in 'metadata', then 'user', then index 0
validation_alias=['metadata', 'user', 0],
schema=core_schema.int_schema()
)
}
)
)

assert v.validate_python({'metadata': {'user': [123, 'other']}}) == {'user_id': 123}

Multiple Alternative Paths

If you provide a list of lists, the validator will try each path in order until it finds a value.

v = SchemaValidator(
core_schema.typed_dict_schema(
fields={
'field_a': core_schema.typed_dict_field(
# Try 'primary_key' first, then fallback to 'legacy_key'
validation_alias=[['primary_key'], ['legacy_key']],
schema=core_schema.int_schema()
)
}
)
)

assert v.validate_python({'primary_key': 1}) == {'field_a': 1}
assert v.validate_python({'legacy_key': 2}) == {'field_a': 2}

Controlling Output with Serialization Aliases

Use serialization_alias to define the key used when converting the object back to a dictionary or JSON.

from pydantic_core import SchemaSerializer, core_schema

s = SchemaSerializer(
core_schema.typed_dict_schema(
{
'cat': core_schema.typed_dict_field(
core_schema.int_schema(),
serialization_alias='Meow'
),
}
)
)

value = {'cat': 0}

# By default, serialization uses internal names
assert s.to_python(value) == {'cat': 0}

# Use by_alias=True to use the serialization_alias
assert s.to_python(value, by_alias=True) == {'Meow': 0}

You can make serialization by alias the default behavior by setting serialize_by_alias=True in CoreConfig.

Error Reporting Locations

The loc_by_alias configuration option determines whether validation errors report the internal field name or the alias path.

from pydantic_core import SchemaValidator, core_schema, CoreConfig, ValidationError
import pytest

v = SchemaValidator(
core_schema.typed_dict_schema(
fields={
'field_a': core_schema.typed_dict_field(
validation_alias='FieldA',
schema=core_schema.int_schema()
)
},
config=CoreConfig(loc_by_alias=True) # Default behavior
)
)

try:
v.validate_python({'FieldA': 'not_an_int'})
except ValidationError as e:
# Error location uses the alias 'FieldA'
assert e.errors()[0]['loc'] == ('FieldA',)

v_no_alias_loc = SchemaValidator(
core_schema.typed_dict_schema(
fields={
'field_a': core_schema.typed_dict_field(
validation_alias='FieldA',
schema=core_schema.int_schema()
)
},
config=CoreConfig(loc_by_alias=False)
)
)

try:
v_no_alias_loc.validate_python({'FieldA': 'not_an_int'})
except ValidationError as e:
# Error location uses the internal name 'field_a'
assert e.errors()[0]['loc'] == ('field_a',)

Troubleshooting

  • Required Fields and Defaults: A field cannot be marked as required=True if it is wrapped in a with_default_schema.
  • Path Constraints: When using a list for validation_alias, the first element must be a string. Subsequent elements can be strings (for dict keys) or integers (for list indices).
  • Config Conflicts: You cannot set both validate_by_alias=False and validate_by_name=False simultaneously, as this would leave the validator with no way to identify the field.
  • Serialization Precedence: The by_alias argument passed directly to to_python or to_json at runtime always takes precedence over the serialize_by_alias setting in CoreConfig.