jquense/yup · error · TypeError
lazy() functions must return a valid schema
Error message
lazy() functions must return a valid schema
What it means
A lazy() schema defers to a getter function that must return a valid yup schema, which is then resolved on demand. Lazy.resolve checks the getter's return value with isSchema() and throws this TypeError if the function returned anything else (or nothing). It exists because lazy is commonly used for recursive structures where a bad return would otherwise fail deep inside validation.
Source
Thrown at src/Lazy.ts:88
clone(spec?: Partial<LazySpec>): Lazy<T, TContext, TFlags> {
const next = new Lazy<T, TContext, TFlags>(this.builder);
next.spec = { ...this.spec, ...spec };
return next;
}
private _resolve = (
value: any,
options: ResolveOptions<TContext> = {},
): Schema<T, TContext, undefined, TFlags> => {
let schema = this.builder(value, options) as Schema<
T,
TContext,
undefined,
TFlags
>;
if (!isSchema(schema))
throw new TypeError('lazy() functions must return a valid schema');
if (this.spec.optional) schema = schema.optional();
return schema.resolve(options);
};
private optionality(optional: boolean) {
const next = this.clone({ optional });
return next;
}
optional(): Lazy<T | undefined, TContext, TFlags> {
return this.optionality(true);
}
resolve(options: ResolveOptions<TContext>) {
return this._resolve(options.value, options);
}View on GitHub (pinned to ff31eee8a2)
Solutions
- Make the lazy getter return a yup schema, e.g. () => yup.string() or () => this.schema().
- If the getter is condition-based, ensure each branch returns a schema rather than relying on a default.
- Check for typos in schema factory calls (yup.objec(), yup.strng()) producing undefined.
Example fix
// before
const s = yup.lazy(() => { schemaDef.required(); })
// after
const s = yup.lazy(() => schemaDef.required()) Defensive patterns
Strategy: type-guard
Validate before calling
import { isSchema } from 'yup';
const safeLazy = (getter) => { const s = getter(); if (!isSchema(s)) throw new TypeError('lazy getter must return a schema'); return yup.lazy(getter); }; Type guard
const isValidLazyGetter = (fn) => isSchema(fn());
Try / catch
try {
return yup.lazy(getter);
} catch (e) {
if (e.message.includes('lazy() functions must return')) {
// inspect what getter() returns
}
throw e;
} Prevention
- Use single-expression arrows in lazy getters: () => yup.string().
- Unit-test lazy schemas by calling resolve on them at startup.
- Keep the getter pure and free of early `return;` statements.
When it happens
Trigger: Calling yup.lazy(fn) where fn returns undefined (missing return), a plain object, a class instance that is not a schema, or a promise/other wrapper instead of a schema.
Common situations: Recursive schemas where the getter has a block body without `return this.schema()`; wrapping lazy around non-yup validators (e.g. a Zod schema); factory functions returning null when a config lookup fails.
Related errors
- conditions must return a schema object
- `array.of()` sub-schema must be a valid yup schema not: ${pr
- either `then:` or `otherwise:` is required for `when()` cond
- ref must be a string, got:
- `${name}` must be a Date or a value that can be `cast()` to
AI-assisted analysis of jquense/yup@ff31eee8a2 (2026-08-31).
Data as JSON: /api/errors/3ef89946ef3c6e65.
Report an issue: GitHub.