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.
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
Stringwithmin_length = 3and a rejecting custom check produces onlytoo_shortwhen 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.
Missing fields and null
Custom validation
? 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.
Ordered callback lists
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, per-call context and its breaking panic-boundary contract, and typed pipelines.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.