yup
>=0.32.0 <2.0.0postconditions9functions7last verified2026-06-23coverage score78%Postconditions: what we check
- validate · validate-rejectserrorWhendata fails validation against the schemaThrows
Promise rejection with ValidationErrorRequired handlingCaller MUST wrap validate() in try-catch or use .catch() handler. Without error handling, validation failures cause unhandled promise rejections that crash the application or lead to silent failures. Use pattern: try { const value = await schema.validate(data); } catch (error) { /* handle */ }costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1] - validateSync · validatesync-throwserrorWhendata fails validation against the schemaThrows
ValidationErrorRequired handlingCaller MUST wrap validateSync() in try-catch block. Without error handling, validation failures throw uncaught exceptions that crash the application. Invalid data will not be caught, leading to data corruption or security vulnerabilities. Use pattern: try { const value = schema.validateSync(data); } catch (error) { /* handle */ }costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[2] - validateSync · validatesync-async-test-throwserrorWhenvalidateSync() is called on a schema that has one or more async test() functions (i.e., test() functions that return a Promise). validateSync() cannot await async tests — when it encounters a Promise-returning test, it throws a plain Error immediately. This is a programmer error: schemas with async validators (e.g., async validators that check uniqueness in the database) must use validate() not validateSync().Throws
Error with message: "Validation test of type: \"<type>\" returned a Promise during a synchronous validate. This test will finish after the validate call has returned" This is a plain Error object, NOT a ValidationError — the schema itself is misconfigured for synchronous use. Confirmed from node_modules/yup/index.js line 386.Required handlingUse validate() (async) instead of validateSync() when the schema has any async test() rules. Common async test patterns in SaaS apps: - Checking uniqueness: schema.test('unique', 'Email taken', async (val) => !(await db.user.findByEmail(val))) - Checking resource existence: schema.test('exists', 'Not found', async (id) => !!(await db.find(id))) These MUST use validate() not validateSync(). Detection pattern: if you see this error in production, find which test() returns a Promise and replace validateSync() with await validate().costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[3] - validateAt · validateat-rejectserrorWhendata at the specified path fails validationThrows
Promise rejection with ValidationErrorRequired handlingCaller MUST wrap validateAt() in try-catch or use .catch() handler. Without error handling, validation failures cause unhandled promise rejections.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[4] - validateSyncAt · validatesyncat-throwserrorWhendata at the specified path fails validationThrows
ValidationErrorRequired handlingCaller MUST wrap validateSyncAt() in try-catch block. Without error handling, validation failures throw uncaught exceptions.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[5] - isValid · isvalid-non-validation-error-rethrowswarningWhenisValid() is called without a catch handler, and a custom test() function in the schema throws a non-ValidationError exception. This occurs when: (a) An async test() makes a database/network call that rejects: schema.test('unique', 'taken', async (val) => !(await db.findByEmail(val))) — if db.findByEmail() throws a DatabaseError, isValid() propagates it. (b) An async test() throws an unexpected TypeError or other runtime error. (c) An async test() throws explicitly (e.g., throw new Error('service unavailable')) instead of returning false. Most developers use isValid() assuming it "always resolves" — it does NOT when non-ValidationError exceptions occur in test functions.Throws
Whatever non-ValidationError the test() function throws. Common cases: - DatabaseError / Prisma errors (when test() checks uniqueness in DB) - NetworkError / FetchError (when test() calls an external API) - TypeError (when test() encounters unexpected input types) - Generic Error (when test() throws new Error(...)) Confirmed from index.js line 930: `throw err` — the error is not wrapped or transformed, it propagates as-is to the caller.Required handlingAlways wrap isValid() in try-catch when the schema contains any test() functions that could throw non-ValidationError exceptions: try { const valid = await schema.isValid(data); if (!valid) { // Validation failed (ValidationError was caught internally) return res.status(400).json({ error: 'Invalid data' }); } // data is valid } catch (error) { // Non-ValidationError from a test() function (DB error, network error, etc.) console.error('Validation service error:', error); return res.status(500).json({ error: 'Validation service unavailable' }); } If you want guaranteed no-throw behavior, use: const valid = await schema.isValid(data).catch(() => false); BUT: this silently treats all errors (including infrastructure outages) as validation failures — use with caution. Best practice: use validate() instead of isValid() in server-side code so validation errors are explicit and infrastructure errors are not swallowed.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[3] - cast · cast-type-errorerrorWhencast() is called without a try-catch, assert is not set to false, and the input value cannot be coerced to the schema's expected type. This occurs when: (a) A string that is not a valid number is cast to number() schema: number().cast('not-a-number') → throws TypeError (NaN is not type 'number') (b) An object with missing required structure is cast to object() schema with strict transforms. (c) External API data with wrong types is cast to a strict schema. Note: number().cast('123') succeeds (returns 123). number().cast('abc') throws. date().cast('not-a-date') throws. object().cast('{"a":1}') may succeed via JSON.Throws
TypeError with message: "The value of <path> could not be cast to a value that satisfies the schema type: \"<type>\". attempted value: <value>" This is a plain TypeError (not a ValidationError). It is thrown synchronously. Confirmed from node_modules/yup/index.js line 772. Note: cast() errors are TypeErrors, not ValidationErrors. Catch blocks that only handle yup.ValidationError will NOT catch cast errors.Required handlingWrap cast() in a try-catch when input may not be safely castable: try { const parsed = schema.cast(rawInput); return { success: true, value: parsed }; } catch (error) { if (error instanceof TypeError) { // Cast failed — input type is fundamentally incompatible with schema console.error('Type cast failed:', error.message); return { success: false, error: 'Invalid data type' }; } throw error; } Alternatively, use assert: false to return null/undefined on failure: const result = schema.cast(value, { assert: false }); if (result == null) { // Cast failed — handle gracefully } Or use validate() instead — it runs the cast AND reports why it failed via ValidationError with a user-readable message.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[3] - cast · cast-transform-throwswarningWhencast() is called and a custom transform() function throws an uncaught error. While rare, custom transforms registered via schema.transform((value, original) => ...) can throw if they encounter unexpected input. This propagates synchronously from cast() without being converted to ValidationError. Also: ObjectSchema.cast() recursively casts nested fields — if any nested field's cast throws, it propagates up from the parent schema's cast().Throws
Whatever the transform() function throws — typically TypeError or plain Error. Not a ValidationError. Propagates synchronously from the cast() call.Required handlingEnsure custom transform() functions handle all edge cases and do not throw. For defensive coding: try { const result = schema.cast(value); } catch (error) { // Handle both TypeError (type check failure) and custom transform errors console.error('Cast failed:', error.message); }costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[3] - ~standard.validate · standard-validate-infrastructure-error-rethrowswarningWhenschema['~standard'].validate(value) is called without a catch handler (typically by integration libraries like react-hook-form's standardResolver, tRPC procedures, conform actions, or TanStack Form validators), and a custom test() function in the schema throws a non-ValidationError exception. Common cases: (a) An async test() makes a database query that rejects: schema.test('unique', 'taken', async (val) => !(await db.findByEmail(val))) — if db.findByEmail() throws, ~standard.validate() propagates the DatabaseError. (b) An async test() calls an external API that rejects (network failure, 5xx). (c) A test() throws unexpectedly (TypeError on bad input access). Standard Schema consumers commonly write code assuming ~standard.validate resolves either { value } or { issues } — they do NOT wrap it in try/catch because the spec implies validation failures are returned as data, not thrown. This assumption is correct for ValidationError but WRONG for infrastructure errors.Throws
Whatever non-ValidationError the test() function throws. Common cases: - DatabaseError / Prisma errors (when test() checks uniqueness in DB) - NetworkError / FetchError (when test() calls an external API) - TypeError (when test() encounters unexpected input types) - Generic Error (when test() throws new Error('service unavailable')) Confirmed from index.js line 1206 (`throw err`) and line 2581 — the error is not wrapped or transformed, it propagates as-is on the returned Promise.Required handlingWhen using the Standard Schema interface directly (rare — usually wrapped by an integration), wrap the call in try-catch: try { const result = await schema['~standard'].validate(rawInput); if (result.issues) { // Validation failed — ValidationError converted to issues[] return { ok: false, errors: result.issues }; } return { ok: true, value: result.value }; } catch (error) { // Non-ValidationError from a test() function (DB error, network error, etc.) // Standard Schema consumers commonly do NOT handle this — infrastructure // failures appear as crashes / 500 errors with no validation context. console.error('Validation infrastructure error:', error); return { ok: false, errors: [{ message: 'Validation service unavailable' }] }; } When using yup via an integration library (react-hook-form standardResolver, tRPC, conform), check the integration's error model — most propagate the rejection as an unhandled promise. Ensure your schema's async test() functions internally try-catch any I/O and return false / a string message instead of throwing. Best practice for schemas with async test() that hit external systems: schema.test('unique', async (val) => { try { return !(await db.findByEmail(val)); } catch (error) { // ✅ Convert infrastructure errors to validation messages console.error('Uniqueness check failed:', error); return new yup.ValidationError('Could not verify email uniqueness', val); } });costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
Sources
Every postcondition cites at least one of these. Grouped by source type; numbered to match the footnotes above.
- [1]github.com/jquense/yupjquense/yup
- [2]github.com/jquense/yupjquense/yup
- [3]github.com/jquense/yupjquense/yup
- [4]github.com/jquense/yupjquense/yup
- [5]github.com/jquense/yupjquense/yup
- [6]github.com/standard-schema/standard-schemastandard-schema/standard-schema
Research notes
Curator notes from SOURCES.md captured when the profile was written so you can verify the reasoning, not just the rules.
yup Contract Sources
Package: yup Contract Version: 1.0.0 Last Verified: 2026-02-26 Maintainer: corpus-team
Overview
Yup is a JavaScript schema validation library for validating object shapes and values. Unlike validator.js (which returns booleans), yup throws ValidationError when validation fails, making proper error handling with try-catch blocks essential.
Critical behavior: All validation methods (validate, validateSync, validateAt, validateSyncAt) throw exceptions on validation failure. Missing error handling causes application crashes.
Official Documentation
Primary Sources
-
GitHub Repository https://github.com/jquense/yup Official source code and documentation
-
API Documentation - Schema Methods https://yup-docs.vercel.app/docs/Api/schema Detailed documentation of validation methods
-
NPM Package https://www.npmjs.com/package/yup Package registry and installation
Validation Methods That Throw Exceptions
1. validate() - Async Validation
Signature: Schema.validate(value: any, options?: object): Promise<InferType<Schema>, ValidationError>
Behavior:
- Returns Promise resolving to validated/parsed value
- Rejects with
ValidationErroron validation failure - Asynchronous - supports async validation rules
Source: https://github.com/jquense/yup#schemavalidatevalue-options-promise
Example:
try {
const validData = await schema.validate(data);
// Use validData
} catch (error) {
if (error instanceof Yup.ValidationError) {
console.error('Validation failed:', error.errors);
}
}
Without try-catch: Unhandled promise rejection crashes application.
2. validateSync() - Sync Validation
Signature: Schema.validateSync(value: any, options?: object): InferType<Schema>
Behavior:
- Synchronously validates and returns parsed value
- Throws
ValidationErrordirectly on failure - Only works if schema has no async tests
Source: https://github.com/jquense/yup#schemavalidatesyncvalue-options-any
Example:
try {
const validData = schema.validateSync(data);
// Use validData
} catch (error) {
if (error instanceof Yup.ValidationError) {
console.error('Validation failed:', error.errors);
}
}
Without try-catch: Uncaught exception crashes application.
3. validateAt() - Async Field Validation
Signature: Schema.validateAt(path: string, value: any, options?: object): Promise<InferType<Schema>, ValidationError>
Behavior:
- Validates specific nested field at given path
- Returns Promise rejecting with
ValidationErroron failure - Asynchronous
Source: https://github.com/jquense/yup#schemavalidateatpath-string-value-any-options-object-promise
Example:
try {
const validEmail = await schema.validateAt('email', formData);
// Valid email
} catch (error) {
if (error instanceof Yup.ValidationError) {
console.error('Email invalid:', error.message);
}
}
Without try-catch: Unhandled promise rejection.
4. validateSyncAt() - Sync Field Validation
Signature: Schema.validateSyncAt(path: string, value: any, options?: object): InferType<Schema>
Behavior:
- Synchronously validates specific nested field
- Throws
ValidationErrordirectly on failure - Only works with synchronous validation rules
Source: https://github.com/jquense/yup#schemavalidatesyncat-path-string-value-any-options-object-any
Example:
try {
const validEmail = schema.validateSyncAt('email', formData);
// Valid email
} catch (error) {
if (error instanceof Yup.ValidationError) {
console.error('Email invalid:', error.message);
}
}
Without try-catch: Uncaught exception.
ValidationError Structure
Source: https://github.com/jquense/yup (README)
Properties:
message- Error message stringerrors- Array of error messagespath- Path to failing field (for nested validations)value- The invalid valueinner- Array ofValidationErrorinstances (whenabortEarly: false)
Example:
catch (error) {
console.log(error.message); // "email must be a valid email"
console.log(error.errors); // ["email must be a valid email"]
console.log(error.path); // "email"
console.log(error.value); // "invalid-email"
console.log(error.inner); // [ValidationError, ValidationError, ...]
}
Validation Options
abortEarly
Type: boolean
Default: true
Behavior:
true: Stop validation on first error (default)false: Validate all fields, return all errors inerror.inner
Source: https://github.com/jquense/yup/issues/44
Example:
try {
await schema.validate(data, { abortEarly: false });
} catch (error) {
// error.inner contains ALL validation errors
error.inner.forEach(err => {
console.log(err.path, err.message);
});
}
Safe Methods (Don't Throw)
isValid() / isValidSync()
Signatures:
Schema.isValid(value: any, options?: object): Promise<boolean>Schema.isValidSync(value: any, options?: object): boolean
Behavior:
- Return
trueif valid,falseif invalid - Never throw exceptions
- Safe for boolean checks without try-catch
Example:
const valid = await schema.isValid(data);
if (!valid) {
// Handle invalid data
}
Key difference: These methods don't throw, but also don't provide error details.
Common Mistakes
1. Missing try-catch on validate()
Source: https://github.com/jquense/yup/issues/144
Wrong:
const data = await schema.validate(input);
// ❌ Unhandled promise rejection crashes app
Right:
try {
const data = await schema.validate(input);
} catch (error) {
// Handle error
}
2. Missing try-catch on validateSync()
Source: https://github.com/jquense/yup/issues/1989
Wrong:
const data = schema.validateSync(input);
// ❌ Uncaught exception crashes app
Right:
try {
const data = schema.validateSync(input);
} catch (error) {
// Handle error
}
3. Confusing isValid() with validate()
Wrong:
try {
const isValid = await schema.isValid(data);
// ⚠️ isValid never throws - try-catch not needed
}
Right:
const isValid = await schema.isValid(data);
if (!isValid) {
// Handle invalid data
}
Security Considerations
Prototype Pollution Vulnerability
CVE: SNYK-JS-YUP-2420835 Affected Versions: < 0.30.0 Fixed Version: 0.30.0
Description: yup is vulnerable to Prototype Pollution via the .setLocale() function.
Source: https://security.snyk.io/vuln/SNYK-JS-YUP-2420835
Proof of Concept:
const payload = JSON.parse('{"__proto__":{"polluted":"Yes"}}');
yup.setLocale(payload);
console.log({}.polluted); // "Yes"
Remediation: Always use yup >= 0.30.0
Note: This vulnerability is unrelated to validation error handling. Contract focuses on ValidationError throwing behavior.
Best Practices
1. Always use try-catch with throwing methods
Source: https://dev.to/buschco/validate-like-a-pro-everywhere-with-yup-2phn
try {
const validData = await schema.validate(data, { abortEarly: false });
// Process validData
} catch (err) {
if (err instanceof Yup.ValidationError) {
// Handle validation errors
const errors = err.inner.reduce((acc, error) => ({
...acc,
[error.path]: error.message
}), {});
}
}
2. Use abortEarly: false for complete error reporting
try {
await schema.validate(data, { abortEarly: false });
} catch (error) {
// error.inner contains all validation errors
error.inner.forEach(err => {
console.log(`${err.path}: ${err.message}`);
});
}
3. Use isValid() for safe boolean checks
// When you only need yes/no, not parsed value
const isValid = await schema.isValid(data);
if (!isValid) {
// Show generic error, don't need details
}
Real-World Usage Examples
Express API Validation
Source: https://gist.github.com/manzoorwanijk/5993a520f2ac7890c3b46f70f6818e0a
app.post('/api/users', async (req, res) => {
try {
const validData = await userSchema.validate(req.body, { abortEarly: false });
// Create user with validData
res.json({ success: true });
} catch (error) {
if (error instanceof Yup.ValidationError) {
res.status(400).json({ errors: error.inner.map(e => ({
field: e.path,
message: e.message
}))});
}
}
});
React Form Validation
Source: https://formik.org/docs/guides/validation
const validationSchema = Yup.object({
email: Yup.string().email().required(),
password: Yup.string().min(8).required()
});
// In form submit handler
try {
const validData = await validationSchema.validate(formData, { abortEarly: false });
// Submit form
} catch (err) {
if (err instanceof Yup.ValidationError) {
const errors = err.inner.reduce((acc, error) => ({
...acc,
[error.path]: error.message
}), {});
setFormErrors(errors);
}
}
Contract Rationale
Why these functions are in the contract:
- validate() - Most commonly used async validation, throws on failure
- validateSync() - Sync validation, throws on failure
- validateAt() - Field-level async validation, throws on failure
- validateSyncAt() - Field-level sync validation, throws on failure
Why these are NOT in the contract:
- isValid() / isValidSync() - Return boolean, never throw exceptions
- cast() - Parsing only, doesn't validate
- describe() - Returns schema metadata, doesn't validate
Key principle: Contract covers all methods that throw ValidationError and require error handling.
References
- Official GitHub: https://github.com/jquense/yup
- API Documentation: https://yup-docs.vercel.app/docs/Api/schema
- Best Practices: https://dev.to/buschco/validate-like-a-pro-everywhere-with-yup-2phn
- Security Advisory: https://security.snyk.io/vuln/SNYK-JS-YUP-2420835
- GitHub Issues (Common Patterns): https://github.com/jquense/yup/issues/144
- Formik Integration: https://formik.org/docs/guides/validation
- React Final Form Example: https://gist.github.com/manzoorwanijk/5993a520f2ac7890c3b46f70f6818e0a
Summary: Yup is exception-based validation. All validate*() methods throw ValidationError on failure and MUST be wrapped in try-catch or use .catch() handlers. Missing error handling causes application crashes.