Profiles·Public

joi

semver>=17.0.0 <19.0.0postconditions11functions7last verified2026-06-24coverage score88%

Postconditions: what we check

  • validate · validate-returns-error
    error
    Whendata fails validation against the schema
    Returns{error: ValidationError, value: any} where error contains validation failure details
    Required handlingCaller MUST check result.error property before using result.value. Without checking error, invalid data will pass through silently, leading to data corruption, business logic errors, or security vulnerabilities. Use pattern: const { error, value } = schema.validate(data); if (error) { /* handle */ }
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[1]
  • validateAsync · validateasync-rejects
    error
    Whendata fails validation against the schema
    ThrowsPromise rejection with ValidationError
    Required handlingCaller MUST wrap validateAsync() in try-catch or use .catch() handler. Without error handling, validation failures cause unhandled promise rejections that crash the application. Use pattern: try { const value = await schema.validateAsync(data); } catch (error) { /* handle */ }
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[2]
  • assert · assert-throws
    error
    Whendata fails validation against the schema
    ThrowsValidationError
    Required handlingCaller MUST wrap Joi.assert() in try-catch block. Without error handling, validation failures throw uncaught exceptions that crash the application. Use pattern: try { Joi.assert(value, schema); } catch (error) { /* handle */ }
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[3]
  • attempt · attempt-throws
    error
    Whendata fails validation against the schema
    ThrowsValidationError
    Required handlingCaller MUST wrap Joi.attempt() in try-catch block. Without error handling, validation failures throw uncaught exceptions that crash the application. Use pattern: try { const validated = Joi.attempt(value, schema); } catch (error) { /* handle */ }
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[4]
  • compile · compile-invalid-schema-throws
    warning
    Whenschema argument is undefined, an empty array, or contains non-plain objects
    ThrowsAssertError (extends Error) from @hapi/hoek — message: 'Invalid undefined schema' or 'Invalid empty array schema' or 'Schema can only contain plain objects'
    Required handlingCaller MUST wrap Joi.compile() in try-catch when schema is built dynamically (e.g. from user input, config files, or database). Static schema definitions compiled at module load are safe if the schema literal is correct. Without error handling, invalid schema definitions throw at runtime and crash the request handler or service startup. Use pattern: try { const schema = Joi.compile(rawSchema); } catch (err) { /* handle */ }
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[5][6]
  • compile · compile-version-mismatch-throws
    warning
    Whenschema was compiled with a different version of joi (legacy: false, default)
    ThrowsAssertError — message: 'Cannot mix different versions of joi schemas: <version> <version>'
    Required handlingWhen using Joi.compile() with dynamically loaded schemas from external sources (plugins, serialized schemas), version mismatches throw AssertError. Use Joi.compile(schema, { legacy: true }) to allow older schema versions, or ensure all schemas are compiled with the same joi version.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[5][6]
  • extend · extend-empty-extensions-throws
    warning
    Whenextend() is called with zero arguments
    ThrowsAssertError from @hapi/hoek — message: 'You need to provide at least one extension'
    Required handlingCaller MUST pass at least one extension definition. When extensions are loaded dynamically (from a plugin loader, config file, or filesystem scan), wrap Joi.extend() in try-catch in case the plugin list is empty after filtering. Without error handling, an empty extension list crashes module initialization. Use pattern: try { customJoi = Joi.extend(...extensions); } catch (err) { /* handle */ }
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[5][7]
  • extend · extend-invalid-extension-shape-throws
    error
    Whenextension object fails Schemas.extension validation (missing type, invalid base, malformed rules)
    ThrowsValidationError from this.assert(extension, Schemas.extension) — wrapped AssertError
    Required handlingCaller MUST validate extension definitions before passing to extend() when extensions come from external sources (user-defined plugins, dynamic config). Each extension must have a string type field and optional base schema, prepare, coerce, validate, rules, and messages fields matching the documented shape. Use pattern: try { customJoi = Joi.extend(extensionDef); } catch (err) { /* handle */ }
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[5][8]
  • extend · extend-override-existing-type-throws
    warning
    Whenextension attempts to define a type name that is not already in the instance's _types set (e.g. trying to override a primitive type name like 'string' without inheriting it as base)
    ThrowsAssertError — message: 'Cannot override name <type>'
    Required handlingWhen extending Joi to add new type names, ensure the name does not collide with built-in primitive types (string, number, boolean, etc.) unless explicitly inheriting via base. Common pitfall when adding a custom 'email' or 'url' type. Use pattern: try { customJoi = Joi.extend({ type: 'myCustomType', base: Joi.string(), ... }); } catch (err) { /* handle */ }
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[7]
  • defaults · defaults-non-function-modifier-throws
    warning
    Whenmodifier argument is not a function (e.g. undefined, object, null)
    ThrowsAssertError from @hapi/hoek — message: 'modifier must be a function'
    Required handlingCaller MUST pass a function as the modifier argument. When the modifier comes from external config or is computed dynamically, validate it is a function before calling Joi.defaults(). Use pattern: try { customJoi = Joi.defaults(modifier); } catch (err) { /* handle */ }
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[5][7]
  • defaults · defaults-modifier-returns-non-schema-throws
    error
    Whenmodifier function returns a value that is not a joi schema object
    ThrowsAssertError from @hapi/hoek — message: 'modifier must return a valid schema object'
    Required handlingModifier function MUST return a joi schema for every input schema. Common mistakes: forgetting to return (returns undefined), returning a plain object instead of calling .object() on it, returning the input unchanged when the modifier mutates instead of returning. Use pattern: Joi.defaults((schema) => schema.required()) — always return the schema.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[5][7]

Sources

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

Official documentation
  • [1]
    joi.dev/api
    Api
  • [2]
    joi.dev/api
    Api
  • [3]
    joi.dev/api
    Api
  • [4]
    joi.dev/api
    Api
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.

Sources: joi

Package: joi Version: 17.x - 18.x Category: validation Last Updated: 2026-02-26 Status: ✅ COMPLETE


Official Documentation

Primary Source

  • API Reference: https://joi.dev/api
    • Comprehensive documentation of all validation methods
    • Error handling patterns and best practices
    • ValidationError structure and properties

Repository

  • GitHub: https://github.com/hapijs/joi
    • Official repository under hapijs organization
    • 21.2k+ stars, actively maintained
    • No active security advisories

Key Behavioral Requirements

1. schema.validate() - Synchronous Validation

Documentation: https://joi.dev/api/?v=17.13.3#anyvalidatevalue-options

Behavior:

  • Returns { error, value, warning, artifacts }
  • Does NOT throw errors (returns error object instead)
  • Must check .error property before using .value

Quote from Docs:

"Returns an object with the following keys: value - the validated and normalized value, error - the validation errors if found."

Risk: Invalid data passes through silently if error is not checked


2. schema.validateAsync() - Asynchronous Validation

Documentation: https://joi.dev/api/?v=17.13.3#anyvalidateasyncvalue-options

Behavior:

  • Returns a Promise
  • Rejects promise on validation failure
  • Must use try-catch or .catch() handler

Quote from Docs:

"Returns a Promise that resolves to the validated value or rejects with validation errors."

Risk: Unhandled promise rejection crashes application


3. Joi.assert() - Assertion-Based Validation

Documentation: https://joi.dev/api/?v=17.13.3#assertvalue-schema-message-options

Behavior:

  • Throws ValidationError on failure
  • No return value (void)
  • Must wrap in try-catch

Quote from Docs:

"Throws on validation failure."

Risk: Application crash on invalid input if not caught


4. Joi.attempt() - Throwing Validation

Documentation: https://joi.dev/api/?v=17.13.3#attemptvalue-schema-message-options

Behavior:

  • Returns validated value on success
  • Throws ValidationError on failure
  • Must wrap in try-catch

Quote from Docs:

"Returns the validated value or throws."

Risk: Application crash on invalid input if not caught


Real-World Usage Examples

Example 1: Docusaurus

Repository: https://github.com/facebook/docusaurus Usage: Configuration and front-matter validation Pattern: Proper error checking with const { error, value } = schema.validate()

File: packages/docusaurus-utils-validation/src/validationUtils.ts

const {error, warning, value} = finalSchema.validate(options, {
  convert: false,
});

printWarning(warning);

if (error) {
  throw error;  // ✅ Properly checks and throws
}

return value;

Example 2: Next.js with-joi Example

Repository: https://github.com/vercel/next.js/tree/canary/examples/with-joi Usage: API request body validation Pattern: Middleware wrapper for validation

File: examples/with-joi/pages/api/people.js

const personSchema = Joi.object({
  age: Joi.number().required(),
  name: Joi.string().required(),
});

router.post(validate({ body: personSchema }), (req, res) => {
  const person = req.body;  // ✅ Middleware handles validation
  return res.status(201).json({ data: person });
});

Security & CVE Analysis

Search Date: 2026-02-26

Sources Checked:

  • GitHub Security Advisories: 0 active advisories
  • Snyk Vulnerability Database: No behavioral CVEs found
  • NVD Database: No relevant entries

Finding: No CVEs found related to validation behavior. The primary risk is developer misuse (not checking errors), not library vulnerabilities.


Common Mistakes

Mistake 1: Not Checking .error Property

// ❌ WRONG
const { value } = schema.validate(data);
doSomething(value);  // May be invalid!

Impact: Invalid data passes through silently Fix: Always check error: if (error) { /* handle */ }

Mistake 2: Missing try-catch for validateAsync()

// ❌ WRONG
const value = await schema.validateAsync(data);  // No try-catch

Impact: Unhandled promise rejection crashes app Fix: Wrap in try-catch block

Mistake 3: Using assert/attempt without try-catch

// ❌ WRONG
Joi.assert(data, schema);  // Will crash if validation fails

Impact: Application crash on invalid input Fix: Wrap in try-catch block


Production Usage Statistics

Analysis Date: 2026-02-26 Repos Analyzed: Docusaurus, Next.js Validation Calls Found: 3 Proper Error Handling: 3 (100%)

Conclusion: High-quality production codebases consistently use proper error handling patterns.


Contract Decisions

Severity: ERROR

All validation methods require error handling because:

  1. validate() - Silent failures lead to invalid data in system
  2. validateAsync() - Unhandled rejections crash applications
  3. assert()/attempt() - Uncaught exceptions crash applications

Scope

Contract covers:

  • schema.validate() - Requires checking .error property
  • schema.validateAsync() - Requires try-catch
  • Joi.assert() - Requires try-catch
  • Joi.attempt() - Requires try-catch

Contract does NOT cover:

  • Schema definition methods (.string(), .object(), etc.)
  • Constraint methods (.required(), .min(), .max(), etc.)
  • Warning handling (warnings are non-fatal)

References

  1. Official API Documentation https://joi.dev/api Comprehensive reference for all methods

  2. Validation Error Structure https://joi.dev/api/#validationerror Details on error object properties

  3. Best Practices Guide https://joi.dev/api/#general-usage Recommended patterns for validation

  4. Production Examples

    • Docusaurus validation utilities
    • Next.js API validation examples

Research Completed: 2026-02-26 Research Files: dev-notes/package-onboarding/joi/.onboarding/research/

Need a different package?
Request a profile