diff --git a/pydantic_xml/serializers/serializer.py b/pydantic_xml/serializers/serializer.py
index ec00561..e44f8b6 100644
--- a/pydantic_xml/serializers/serializer.py
+++ b/pydantic_xml/serializers/serializer.py
@@ -189,7 +189,11 @@ def preprocess_schema(cls, schema: pcs.CoreSchema, ctx: Context) -> Tuple[pcs.Co
elif schema_type == 'nullable':
ctx = ctx.replace(optional=True)
- inner_schema = schema['schema']
+ if schema_type == 'function-plain':
+ inner_schema = schema['serialization']
+ else:
+ inner_schema = schema['schema']
+
return cls.preprocess_schema(inner_schema, ctx)
elif type_family is SchemaTypeFamily.JSON_OR_PYTHON:
diff --git a/tests/test_preprocessors.py b/tests/test_preprocessors.py
index 52ed990..1a0b2fd 100644
--- a/tests/test_preprocessors.py
+++ b/tests/test_preprocessors.py
@@ -1,3 +1,4 @@
+import datetime as dt
from typing import Any, Dict, List
import pydantic as pd
@@ -105,3 +106,20 @@ def validate_model(self) -> 'TestModel':
with pytest.raises(ValueError) as err:
TestModel.from_xml(xml)
assert err.value.errors()[0]['ctx']['orig'] == 'Value error, text'
+
+
+def test_plain_validator():
+ class TestModel(BaseXmlModel, tag='model1'):
+ element1: dt.date = element()
+
+ @pd.field_validator('element1', mode='plain')
+ def validate_element1(cls, value: Any) -> Any:
+ return dt.datetime.strptime(value, '%Y%m%d').date()
+
+ xml = '20260517'
+ model = TestModel.from_xml(xml)
+ assert model.element1 == dt.date(2026, 5, 17)
+
+ with pytest.raises(ValueError) as err:
+ xml = 'aabb'
+ TestModel.from_xml(xml)