Profiles·Public

yup

semver>=0.32.0 <2.0.0postconditions9functions7last verified2026-06-23coverage score78%

Postconditions: what we check

  • validate · validate-rejects
    error
    Whendata fails validation against the schema
    ThrowsPromise rejection with ValidationError
    Required 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 unavailablevisibilityvisible
    Sources[1]
  • validateSync · validatesync-throws
    error
    Whendata fails validation against the schema
    ThrowsValidationError
    Required 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 unavailablevisibilityvisible
    Sources[2]
  • validateSync · validatesync-async-test-throws
    error
    WhenvalidateSync() 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().
    ThrowsError 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 unavailablevisibilityvisible
    Sources[3]
  • validateAt · validateat-rejects
    error
    Whendata at the specified path fails validation
    ThrowsPromise rejection with ValidationError
    Required handlingCaller MUST wrap validateAt() in try-catch or use .catch() handler. Without error handling, validation failures cause unhandled promise rejections.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[4]
  • validateSyncAt · validatesyncat-throws
    error
    Whendata at the specified path fails validation
    ThrowsValidationError
    Required handlingCaller MUST wrap validateSyncAt() in try-catch block. Without error handling, validation failures throw uncaught exceptions.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[5]
  • isValid · isvalid-non-validation-error-rethrows
    warning
    WhenisValid() 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.
    ThrowsWhatever 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 unavailablevisibilityvisible
    Sources[3]
  • cast · cast-type-error
    error
    Whencast() 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.
    ThrowsTypeError 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 unavailablevisibilityvisible
    Sources[3]
  • cast · cast-transform-throws
    warning
    Whencast() 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().
    ThrowsWhatever 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 unavailablevisibilityvisible
    Sources[3]
  • ~standard.validate · standard-validate-infrastructure-error-rethrows
    warning
    Whenschema['~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.
    ThrowsWhatever 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[6][3]

Sources

Every postcondition cites at least one of these. Grouped by source type; numbered to match the footnotes above.

Source code

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

  1. GitHub Repository https://github.com/jquense/yup Official source code and documentation

  2. API Documentation - Schema Methods https://yup-docs.vercel.app/docs/Api/schema Detailed documentation of validation methods

  3. 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 ValidationError on 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 ValidationError directly 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 ValidationError on 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 ValidationError directly 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 string
  • errors - Array of error messages
  • path - Path to failing field (for nested validations)
  • value - The invalid value
  • inner - Array of ValidationError instances (when abortEarly: 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 in error.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 true if valid, false if 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:

  1. validate() - Most commonly used async validation, throws on failure
  2. validateSync() - Sync validation, throws on failure
  3. validateAt() - Field-level async validation, throws on failure
  4. 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


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.

Need a different package?
Request a profile