Install & Compatibility
Where this runs
tested against v2.21.1 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.910 runs
installs and imports cleanly · install 0.0s · import 0.482s · 40.2MB
glibcpy 3.10–3.910 runs
installs and imports cleanly · install 3.6s · import 0.441s · 40MB
38MB installed
● package 38MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
BaseXmlModel
✓ from pydantic_xml import BaseXmlModel
RootXmlModel
✓ from pydantic_xml import RootXmlModel
Required for custom root types and models that directly represent the XML root element.
attr
✓ from pydantic_xml import attr
✗ from pydantic_xml.elements import attr
Top-level import is preferred for convenience and stability.
element
✓ from pydantic_xml import element
✗ from pydantic_xml.elements import element
Top-level import is preferred for convenience and stability.
wrapped
✓ from pydantic_xml import wrapped
✗ from pydantic_xml.elements import wrapped
Top-level import is preferred for convenience and stability. Used for deep element hierarchies without intermediate models.
This example demonstrates how to define XML serializable/deserializable models using `BaseXmlModel`, bind fields to XML attributes (`attr`), elements (`element`), and handle lists of sub-models. It covers both deserialization from an XML string and serialization back to XML.
from typing import List, Optional
from pydantic import HttpUrl
from pydantic_xml import BaseXmlModel, attr, element
class Product(BaseXmlModel):
status: str = attr() # e.g., 'running', 'development'
launched: Optional[int] = attr(default=None)
title: str # Extracted from the element text
class Company(BaseXmlModel, tag='Company'):
trade_name: str = attr(name='trade-name')
website: HttpUrl = element()
products: List[Product] = element(tag='product', default_factory=list)
xml_doc = """
<Company trade-name="SpaceX">
<website>https://www.spacex.com</website>
<product status="running" launched="2013">Several launch vehicles</product>
<product status="running" launched="2019">Starlink</product>
<product status="development">Starship</product>
</Company>
"""
# Deserialize XML to a Pydantic model
company = Company.from_xml(xml_doc)
print(f"Company: {company.trade_name}, Website: {company.website}")
for product in company.products:
print(f" Product: {product.title}, Status: {product.status}, Launched: {product.launched}")
# Serialize Pydantic model back to XML
new_xml_doc = company.to_xml(pretty_print=True)
print("\nSerialized XML:")
print(new_xml_doc.decode())
Debug
Known issues
breakingMigration to Pydantic V2 (from Pydantic V1) requires significant changes. `pydantic-xml` 2.x supports Pydantic V2+. While `pydantic-xml` itself aims for compatibility, direct Pydantic V1 (`pydantic.v1.BaseModel`) and Pydantic V2 (`pydantic.BaseModel`) models cannot be mixed directly within the same hierarchy.fixUpgrade Pydantic to V2, migrate your Pydantic models, and ensure all models used with `pydantic-xml` are Pydantic V2 compatible. Avoid mixing `pydantic.v1.BaseModel` and `pydantic.BaseModel` in model hierarchies. Use `bump-pydantic` tool for initial migration of Pydantic models.
affects: Pydantic < 2.0 to Pydantic >= 2.0.0
breakingSince v2.16.0, an exception is now raised if a namespace alias used in a model or field is not found within the model's namespace map (`__xml_nsmap__`). This changed behavior from silently ignoring missing aliases.fixEnsure all namespace aliases used in `ns` or `nsmap` parameters are correctly defined in the model's `__xml_nsmap__` class attribute.
affects: >=2.16.0
breakingThe way custom root types are declared changed significantly around `pydantic-xml` 2.0.0. Custom root models must now inherit from `RootXmlModel` instead of `BaseXmlModel` with `__root__` attribute.fixChange base class from `BaseXmlModel` to `RootXmlModel` for models representing the root of an XML document and defining a `root` field for the content.
affects: >=2.0.0
gotchaBy default, `pydantic-xml` maps Python field names directly to XML element/attribute names. If the XML tag or attribute name differs (e.g., due to different casing or hyphens), `ParsingError` will be raised unless `tag` or `name` arguments are explicitly provided to `element()`, `attr()`, or `BaseXmlModel`.fixAlways explicitly specify `tag='your-xml-tag'` for elements or `name='your-xml-attribute'` for attributes, and `tag='YourRootTag'` for `BaseXmlModel` if the XML names don't exactly match Python field/class names or casing.
affects: All versions
gotchaThe syntax for defining custom field serializers and validators has evolved with Pydantic V2. While older `@xml_field_serializer` and `@xml_field_validator` decorators are still functional, the `Annotated` pattern with `pydantic.field_serializer` and `pydantic.field_validator` (or `pydantic.BeforeValidator`, `pydantic.AfterValidator`, etc.) is the recommended Pydantic V2 approach for better integration and type safety.fixPrefer using `typing.Annotated` with Pydantic's functional validators/serializers (`field_serializer`, `field_validator`, `AfterValidator`, etc.) for defining custom serialization/validation logic.
affects: >=2.17.0 (for new syntax support)
breakingThe encoding format for `bool` and `None` types changed. `bool` values now serialize as lowercase `'true'` or `'false'` instead of title-case `'True'` or `'False'`. `None` values now serialize as an empty string `''` instead of `'None'`.fixUpdate any downstream consumers of XML generated by `pydantic-xml` to expect the new `bool` and `None` encoding formats. If the old format is strictly required, implement custom serializers for these types.
affects: >=2.9.0
Errors
Common errors & fixes
pydantic_xml.errors.ParsingError: root element not found (actual: {namespace}tag, expected: tag)
The XML document's root element tag or its namespace does not match the `tag` and `nsmap` configured in the `BaseXmlModel` definition.
fixEnsure the `tag` parameter in your `BaseXmlModel` matches the actual XML root tag (case-sensitive) and include the correct `nsmap` dictionary if the XML uses namespaces. For a default namespace, use an empty string as the key in `nsmap`.
AttributeError: module 'pydantic_core' has no attribute 'TuplePositionalSchema'
This error occurs due to an incompatibility between your installed `pydantic-xml` version and a newer version of `pydantic_core` (Pydantic v2.16+), where internal schema classes were renamed or removed.
fixUpgrade `pydantic-xml` to its latest version (which supports newer Pydantic versions) or, if an upgrade is not immediately possible, downgrade `pydantic` and `pydantic_core` to compatible versions (e.g., `pydantic<2.6` and `pydantic_core<2.16` for older `pydantic-xml` versions).
pydantic_core._pydantic_core.ValidationError: 1 validation error for ModelName FieldName [line -1]: Field required
The XML input is missing a required element or attribute that is defined as a non-optional field in the `pydantic-xml` model, or the field is incorrectly mapped (e.g., expecting an element but receiving an attribute, or vice versa).
fixReview the XML structure and your `pydantic-xml` model definition. Ensure all required fields are present in the XML and correctly mapped using `attr()`, `element()`, or `text()`. If a field might be optional in the XML, declare it as `Optional` in your model.
Upgrade
Version history
2.21.1latest on PyPI · released Aug 8, 2026
Audit
Dependencies
pydanticrequiredCore dependency for model definition and validation.
lxmloptionalOptional dependency for faster XML parsing and serialization, otherwise defaults to xml.etree.ElementTree.