Skip to content

validateFields

validateFields(props): Promise<void>

Defined in: packages/core/src/fields/validate.ts:38

Runs each changed field’s validate() against the merged document, skipping fields whose key isn’t in keys (unchanged on update, every field on create), that don’t define validate, or whose admin.condition evaluates false — a condition-hidden field’s validate() never runs, matching getFieldsInputSchema’s schema-level skip (Step 9). doc stands in for both data and siblingData here: validateFields only ever runs a TOP-LEVEL field’s own validate() (a group/array/blocks sub-field’s validate(), if any, runs through the container field’s own value, not individually), so the two are the same object at this depth — exactly like getFieldsInputSchema’s top-level fields, where siblingData is data itself.

A field reports failure by throwing, not by returning a message: a thrown error carries a stack, can be a project’s own error subclass, and can attach arbitrary structured data through ConvexError. A returned string could carry none of that, and made the success path (return undefined) easy to hit by accident.

Whatever a field throws is re-thrown as a ConvexError carrying the field key, so the admin panel can attribute the failure to one input. A ConvexError’s own data is preserved verbatim — an object payload is merged with field, a plain-string payload becomes message — so a project can surface codes or hints of its own.

The resource’s field map (a collection’s or a global’s), resolved document, changed field keys, mutation ctx, and resolved config (needed to build the vex api each callback receives).

VexConfig

VexMutationCtx

Record<string, unknown>

Record<string, AdminField>

Iterable<string>

Promise<void>

Nothing; resolves once every applicable field’s validate() has passed.

With { field, message, ... } for the first field that throws.