How to Use Validated Mode

By default, arrowmodel uses Pydantic’s model_construct to build model instances without running validation. This is the fast path – it trusts that the Arrow data matches the model’s schema. When you need Pydantic’s full validation pipeline (type coercion, custom validators, field constraints), pass validate=True.

Enable validated mode

Every API style accepts a validate keyword argument:

import pyarrow as pa
from pydantic import BaseModel
from arrowmodel import ArrowModel, ArrowModelConverter, model_convert


class User(BaseModel):
    id: int
    name: str
    score: float


batch = pa.record_batch(
    {
        "id": [1, 2, 3],
        "name": ["Alice", "Bob", "Carol"],
        "score": [9.5, 8.0, 7.3],
    }
)

# Convenience function
users = model_convert(User, batch, validate=True)

# Converter object
converter = ArrowModelConverter(User, validate=True)
users = converter.convert(batch)


# ArrowModel base class
class ValidatedUser(ArrowModel):
    id: int
    name: str
    score: float


users = ValidatedUser.convert(batch, validate=True)

All three produce the same result. The difference is that each row is serialised to JSON in Rust and then passed through Pydantic’s model_validate_json – the same pipeline that runs when you call User.model_validate_json(json_bytes) in plain Pydantic.

What validation catches

The validated path runs Pydantic’s full validation, including:

  • Type coercion – string "42" in an int field becomes 42 (or raises, depending on your model_config).

  • Custom validators@field_validator and @model_validator decorators fire as expected.

  • Field constraintsField(ge=0, le=100) bounds are enforced.

  • Strict mode – if the model uses model_config = ConfigDict(strict=True), no coercion is applied and type mismatches raise ValidationError.

Note

The fast path (validate=False) skips all of this. Values are placed directly into model fields as extracted from Arrow buffers. If a column contains unexpected data, you will not get a ValidationError – you will get a model instance with the wrong value. See Understanding Fast Path vs Validated Path for a deeper discussion.

Performance trade-off

Validation adds overhead because each row is serialised to JSON bytes and then parsed by Pydantic. Expect roughly 2-5x slower conversion compared to the fast path, depending on model complexity.

The rule of thumb:

  • Fast path (validate=False) – use when the data source is trusted (your own database, an internal service, a file you wrote).

  • Validated path (validate=True) – use when the data source is untrusted or when you need custom validators to run (user uploads, third-party APIs, data you did not produce).

Handle validation errors

When validation fails, Pydantic raises its standard ValidationError. Catch it the same way you would with model_validate_json:

from pydantic import BaseModel, ValidationError
from arrowmodel import model_convert


class StrictAge(BaseModel):
    age: int


# Arrow column has strings where ints are expected
bad_batch = pa.record_batch({"age": pa.array(["not_a_number"])})

try:
    model_convert(StrictAge, bad_batch, validate=True)
except ValidationError as exc:
    print(exc)
    # 1 validation error for StrictAge
    # age
    #   Input should be a valid integer ... (type=int_parsing)

The error surfaces on the first row that fails validation. The remaining rows are not processed.

Warning

ValidationError is only raised in validated mode. The fast path does not validate and will not raise ValidationError regardless of the data.