> ## Documentation Index
> Fetch the complete documentation index at: https://rydantic.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Fields and validation

> Supported types, normalization, constraints, missing values and custom rules.

Supported types include `String`, borrowed `&str` and `Cow<str>`, `bool`, signed and unsigned 8/16/32/64/128-bit integers, `isize`, `usize`, `f32`, `f64`, `Option<T>`, `Box<T>`, `Vec<T>`, `[T; N]`, string-keyed `BTreeMap` and `HashMap`, `serde_json::Value`, source-preserving `Box<RawValue>`, and nested, recursive, and generic models.

| Field attribute | Behavior |
| - | - |
| `trim`, `lowercase`, `uppercase` | Normalize strings through a fixed pipeline |
| `coerce` | Convert numeric strings to numbers, `"true"`/`"false"` to booleans, and numbers/booleans to strings |
| `min_length`, `max_length` | Count Unicode scalar values in strings, collection elements, or map entries |
| `ge`, `gt`, `le`, `lt` | Apply numeric bounds using number literals or exact decimal strings |
| `pattern = "..."` | Use Rust regex syntax; patterns are checked at compile time and cached at runtime |
| `email` | Validate email addresses with `email_address` |
| `default` | Use the field type's `Default::default()` |
| `default = expression` | Use an explicit default; string literals can be used directly for String fields |
| `default_factory = path` | Call a factory whenever the field is missing |
| `required` | Require the field to appear in the input, including Option fields |
| `rename = "..."` | Set both input and output names |
| `validation_alias`, `serialization_alias` | Set input and output names separately |
| `exclude` | Omit the field from output and the output schema; input rules still apply |
| `before = path` | Transform the raw JSON value before type decoding |
| `validate = path` | Run a custom validator after constructing the typed field |
| `description = "..."` | Add a schema description; field documentation comments are also read automatically |
| `flatten` | Merge a named model or string-keyed map into the current JSON object |
| `extra` | Capture unknown fields in a map, together with container-level `extra = "allow"` |
| `async_validate = path` | Await an asynchronous field validator |

Container attributes: `extra = "forbid"` (default), `extra = "ignore"`, `extra = "allow"`, `title = "..."`, `validate = path`, `async_validate = path`, and `tag = "..."` or `untagged` for enums.

The parsing pipeline is: read input or produce a default → before callback → type decoding and explicit coercion → trim → case conversion → field constraints → custom field validation → custom model validation. Defaults follow the same pipeline. Errors from independent fields are collected together; a parent model's custom validator runs after all its fields succeed.

Numeric strings require explicit `coerce`. A JSON number such as `25.0` is accepted for an integer, while `25.5` fails, following JSON Schema's definition of mathematical integers. Range comparisons preserve 128-bit integer precision, and extremely large exponents are processed with bounded work. Floating-point values follow Rust's IEEE 754 representations; NaN, infinity, and values outside the target type's range fail validation.

## Construction versus revalidation

`before(Value) -> Result<Value, ValidationError>` transforms construction input, not an already constructed Rust value. Its output still has to decode into the declared field type. Defaults also pass through this construction pipeline; a `before` callback cannot bypass type checks.

`validate(&T) -> Result<(), ValidationError>` is a typed check, not a transformer. Model callbacks take `&Self` and return `Result<(), ValidationErrors>`. `validate()` and dump methods recheck existing values without rerunning `before`, trimming or changing case. Use parsing to construct normalized values; do not expect dumping to repair an invalid or unnormalized instance.

The current field-callback gates differ between construction and revalidation:

* Parsing skips a field's custom check if decoding or that field's built-in constraints fail.
* Revalidation skips the custom check when validation of the field's type or nested value fails. If that succeeds, built-in constraints and the custom check both run, even if a built-in constraint reports an error.
* For example, a `String` with `min_length = 3` and a rejecting custom check produces only `too_short` when parsing `"x"`, but both errors when validating the directly constructed Rust value. Both entry points reject it; the difference is callback execution and diagnostics, not validation bypass.
* Independent sibling errors accumulate, and a model's custom check runs only when all of its field checks succeed. A single model callback may return multiple errors.

These synchronous rules also govern the synchronous phase of the async entry points. Callbacks with side effects should not assume identical invocation counts between parse, validate and dump.

## Missing fields and null

| Declaration | May be omitted | Accepts null |
| - | - | - |
| `name: String` | No | No |
| `name: Option<String>` | Yes, produces None | Yes |
| `#[model(required)] name: Option<String>` | No | Yes |
| `#[model(default = "guest")] name: String` | Yes, uses the default | No |

## Custom validation

```rust theme={"system"}
use rydantic::{Model, ValidationError, ValidationErrors, Value};

fn expand(value: Value) -> Result<Value, ValidationError> {
    if value == "many" { Ok(rydantic::json!(10)) } else { Ok(value) }
}

fn even(value: &u32) -> Result<(), ValidationError> {
    if value.is_multiple_of(2) { Ok(()) }
    else { Err(ValidationError::new("even", "value must be even")) }
}

fn check_window(value: &Window) -> Result<(), ValidationErrors> {
    if value.end >= value.start { Ok(()) }
    else { Err(ValidationError::custom("end must be >= start").at("end").into()) }
}

#[derive(Model)]
#[model(validate = check_window)]
struct Window {
    start: u32,
    #[model(before = expand, validate = even)]
    end: u32,
}
```

Stable 0.7.0 supports the single callback paths shown above. Ordered lists and context-aware variants require the 0.8.0-beta.1 APIs described below. For custom fail-fast control flow on either version, compose checks inside an ordinary Rust function:

```rust theme={"system"}
fn valid_end(value: &u32) -> Result<(), ValidationError> {
    even(value)?;
    if *value <= 100 { Ok(()) }
    else { Err(ValidationError::custom("end must be <= 100")) }
}
// Use #[model(validate = valid_end)].
```

Here `?` stops this callback at its first failure; it does not stop validation of independent sibling fields. The plain callback signatures above remain context-free. The beta-only explicit `*_with_context` callback attributes additionally receive `&Context`, including per-call application data when supplied through a context entry point. Cross-field checks belong in a model callback, which receives the fully constructed model. These derive attributes do not suppress or retry typed decoding; typed pipeline adapters are a separate API.

Custom error paths are automatically prefixed with the parent path when nested. `ValidationErrors::errors()` returns an error slice, and `to_json()` returns structured JSON. Each error includes `loc`, `code`, `message`, `stage`, and constraint parameters; `pointer()` returns an escaped JSON Pointer.

```json theme={"system"}
[
  {
    "loc": ["addresses", 0, "city"],
    "code": "too_short",
    "message": "length must be >= 2",
    "stage": "validate",
    "params": {"actual": 1, "limit": 2}
  }
]
```

## Ordered callback lists

> [!NOTE]
>
> **Requires 0.8.0-beta.1, not stable 0.7.0.** These lists and the context variants below are available in the opt-in prerelease. Install with `rydantic = "=0.8.0-beta.1"`. See [release status](/reference/releases), [per-call context and its breaking panic-boundary contract](/models/validation-context), and [typed pipelines](/models/validator-extensions).

Each callback attribute accepts either a function path or a nonempty list of paths:

```rust theme={"system"}
#[model(validate = [check_relationships, check_business_rules])]
struct Request {
    #[model(before = [strip_prefix, normalize_input], validate = [check_format, check_policy])]
    value: String,
}
```

`before` transforms run left to right, passing each output to the next. The first error stops that field's transform chain; independent siblings still run. Typed `validate` and `async_validate` lists run all checks in declared order and accumulate their errors. The prerequisite gate is evaluated once before the list, not again after each callback. Construction skips the entire field check list after decoding or built-in constraint failure; revalidation preserves the different gate documented above. Model lists run only after successful field checks. Async lists are sequential and begin only after the nested async checks succeed. A failing check in a list does not skip later checks in that same list. Empty lists, non-path elements, and duplicate attributes are compile errors.

For per-call data, the explicit `before_with_context`, `validate_with_context`, and `async_validate_with_context` variants accept the same paths or lists and add `&Context` as the final callback argument. Their return types and gates are unchanged. Do not combine a plain and context variant of the same phase on one field or model; use context callbacks wrapping context-free helpers if needed. Context callbacks cannot mutate the error collection directly: return errors, and generated code assigns the current field/model path once.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.