Guides

FAQ

Short answers to common questions.

schema! or #derive(Validate)?

Both generate the same API. schema! needs no proc-macro and keeps the schema next to the type in one line per field. The derive (feature derive) fits structs that already carry other derives and attributes, supports #[serde(skip)] / default, and generic structs. The derive's parse method is vld_parse() (not parse()) to avoid clashing with clap::Parser::parse.

Why is vld::date() missing?

It exists only when exactly one of the chrono, jiff, time features is enabled. Another crate in your tree may have enabled a second backend. Use vld::chrono::date() (or the backend you use). See Dates.

Why does my runtime limit not change?

Field schemas in schema! / derive structs are built once per process. A value read from configuration is frozen at the first parse. Build such schemas at runtime with vld::object(). See Performance.

How do I return a schema from a function?

Return impl vld::Schema<Output = T>. A plain impl VldSchema hides the JSON Schema traits, so with the openapi feature the result cannot be used as an object or schema! field:

fn username() -> impl vld::Schema<Output = String> {
    vld::string().min(3).max(20).alphanumeric()
}

vld::Schema is VldSchema plus, with openapi, JsonSchema and CollectNestedSchemas.

T::vld_parse_value is not found

#[derive(Validate)] and schema! types have an inherent vld_parse_value (and parse_value), so MyType::vld_parse_value works without importing anything. For a generic T: VldParse it comes from the bound.

The compiler says my schema is not Send / Sync / 'static

Same cause: cached field schemas live in a static. Closures in refine, transform or custom must not capture references to local data; move owned data in or use constants.

How do I accept "42" for a number field in JSON?

Use .coerce(): vld::number().coerce(), vld::u32().coerce(), vld::boolean().coerce(). Web query, path, form, header and cookie values are coerced automatically.

How do I reject unknown fields?

vld::object().strict() rejects them with unrecognized_field. schema! and derive structs ignore unknown keys.

Why does a missing field say "Required field is missing" but null says "Expected string, received null"?

Since 0.5 an absent key reports missing_field and a present null reports invalid_type, so clients can tell the two apart. Make the field .optional(), .nullable() or .with_default(..) to accept both.

How do I get the error code in my frontend?

The web adapters include code (the stable IssueCode::key()) in every issue of the 422 body. In Rust, call issue.code.key().

Can I validate a struct I already have?

Yes: User::validate(&user) for schema! / derive types (the value must implement Serialize), impl_rules! for any struct, or schema.validate(&value) for a single schema. See Parse vs validate.

Does vld work in WebAssembly?

The core has no platform-specific code; the UI integrations (vld-leptos, vld-dioxus) are built for wasm32 in CI. Features that touch the filesystem (path().exists(), file()) are not meaningful in a browser.

Is there a TypeScript version of my schemas?

vld-ts generates Zod or Valibot code from vld schemas, so client and server validate the same rules.

Where are the API docs?

On docs.rs/vld. Each integration crate links its own docs.rs page from its integration page.