or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-ajv-errors

Custom error messages in JSON Schemas for Ajv validator

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/ajv-errors@3.0.x

To install, run

npx @tessl/cli install tessl/npm-ajv-errors@3.0.0

index.mddocs/

ajv-errors

ajv-errors is a plugin for the Ajv JSON Schema validator (v8+) that enables custom error messages in JSON schemas. It allows developers to replace Ajv's default validation error messages with user-friendly, contextual messages that can include templated values from the validated data.

Package Information

  • Package Name: ajv-errors
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install ajv-errors

Core Imports

import ajvErrors from "ajv-errors";
import Ajv from "ajv";

For CommonJS:

const ajvErrors = require("ajv-errors");
const Ajv = require("ajv").default;

Basic Usage

import ajvErrors from "ajv-errors";
import Ajv from "ajv";

// Create Ajv instance with required configuration
const ajv = new Ajv({ allErrors: true });

// Add ajv-errors plugin
ajvErrors(ajv, { keepErrors: false, singleError: false });

// Use errorMessage in schema
const schema = {
  type: "object",
  required: ["name", "age"],
  properties: {
    name: { type: "string", minLength: 2 },
    age: { type: "number", minimum: 0 }
  },
  additionalProperties: false,
  errorMessage: "Should be a person object with valid name and age"
};

const validate = ajv.compile(schema);
const isValid = validate({ name: "A", age: -1 });
console.log(validate.errors); // Custom error message instead of default ones

Architecture

ajv-errors works by:

  • Keyword Registration: Adds the errorMessage keyword to Ajv instances
  • Error Interception: Captures validation errors generated by other keywords
  • Message Replacement: Replaces captured errors with custom messages
  • Template Processing: Supports JSON pointer interpolation in error messages
  • Flexible Configuration: Supports various error message patterns and merging options

Capabilities

Plugin Registration

Main function to add custom error message support to an Ajv instance.

/**
 * Adds errorMessage keyword support to an Ajv instance
 * @param ajv - Ajv validator instance (must have allErrors: true)
 * @param options - Configuration options for error message behavior
 * @returns The same Ajv instance with errorMessage keyword added
 * @throws Error if allErrors is false or jsPropertySyntax is true
 */
function ajvErrors(ajv: Ajv, options?: ErrorMessageOptions): Ajv;

interface ErrorMessageOptions {
  /** Keep original errors alongside custom messages (default: false) */
  keepErrors?: boolean;
  /** Merge multiple errors into single error (default: false) */
  singleError?: boolean | string;
}

Error Message Schema Types

The errorMessage keyword accepts various formats for different use cases.

interface ErrorMessageSchema {
  /** Custom messages for property-specific errors */
  properties?: { [propertyName: string]: string };
  /** Custom messages for array item errors by index */
  items?: string[];
  /** Custom messages for required property errors */
  required?: string | { [propertyName: string]: string };
  /** Custom messages for dependency errors */
  dependencies?: string | { [propertyName: string]: string };
  /** Default fallback message for unspecified errors */
  _?: string;
  /** Custom messages for specific validation keywords */
  [keyword: string]: string | { [propertyName: string]: string } | string[] | undefined;
}

Single Message Format

Replace all validation errors with one custom message.

// String format - replaces all errors
const schema = {
  type: "object",
  required: ["foo"],
  properties: { foo: { type: "integer" } },
  additionalProperties: false,
  errorMessage: "Should be an object with an integer property foo only"
};

Keyword-Specific Messages

Replace errors from specific validation keywords.

// Object format - keyword-specific messages
const schema = {
  type: "object",
  required: ["foo"],
  properties: { foo: { type: "integer" } },
  additionalProperties: false,
  errorMessage: {
    type: "Should be an object",
    required: "Should have property foo",
    additionalProperties: "Should not have extra properties"
  }
};

Property and Item Messages

Replace errors for specific properties or array items.

// Property-specific messages
const schema = {
  type: "object",
  properties: {
    name: { type: "string", minLength: 2 },
    age: { type: "number", minimum: 0 }
  },
  errorMessage: {
    properties: {
      name: "Name must be a string with at least 2 characters",
      age: "Age must be a non-negative number"
    }
  }
};

// Array item messages
const schema = {
  type: "array",
  items: [
    { type: "string" },
    { type: "number" }
  ],
  errorMessage: {
    items: [
      "First item must be a string",
      "Second item must be a number"
    ]
  }
};

Property-Specific Required Messages

Different messages for different required properties.

const schema = {
  type: "object",
  required: ["name", "email"],
  properties: {
    name: { type: "string" },
    email: { type: "string", format: "email" }
  },
  errorMessage: {
    required: {
      name: "Name is required",
      email: "Email address is required"
    }
  }
};

Template Interpolation

Use JSON pointers to include data values in error messages.

const schema = {
  type: "object",
  properties: {
    price: { type: "number", minimum: 0 }
  },
  errorMessage: {
    properties: {
      price: "Price must be non-negative, got ${/price}"
    }
  }
};

// For property names, use relative JSON pointer
const schema = {
  type: "object",
  additionalProperties: {
    not: true,
    errorMessage: "Extra property ${0#} is not allowed"
  }
};

Default Message

Use _ property for fallback messages when using object format.

const schema = {
  type: "object",
  required: ["name"],
  properties: {
    name: { type: "string" }
  },
  errorMessage: {
    type: "Must be an object",
    properties: {
      name: "Name must be a string"
    },
    _: "Object validation failed"  // Catches any other errors
  }
};

Types

interface ErrorMessageOptions {
  /** 
   * Keep original errors alongside custom messages
   * - false (default): Remove original errors (available in params.errors)
   * - true: Keep original errors, mark replaced ones with emUsed: true
   */
  keepErrors?: boolean;
  
  /** 
   * Merge multiple error messages into single error
   * - false (default): Create separate error for each message
   * - true: Merge with "; " separator
   * - string: Use custom separator for merging
   */
  singleError?: boolean | string;
}

interface ErrorMessageSchema {
  /** Custom messages for property validation errors */
  properties?: { [propertyName: string]: string };
  /** Custom messages for array item validation errors by index */
  items?: string[];
  /** Custom messages for required field validation errors */
  required?: string | { [propertyName: string]: string };
  /** Custom messages for dependency validation errors */
  dependencies?: string | { [propertyName: string]: string };
  /** Default message for errors not handled by other properties */
  _?: string;
  /** Custom messages for any validation keyword */
  [keyword: string]: string | { [propertyName: string]: string } | string[] | undefined;
}

Error Output Structure

When ajv-errors processes validation errors, it generates new error objects:

// Generated error structure
interface CustomErrorObject {
  keyword: "errorMessage";
  message: string;                    // Your custom error message
  instancePath: string;               // JSON pointer to invalid data
  schemaPath: string;                 // JSON pointer to schema location
  params: {
    errors: ErrorObject[];            // Original validation errors that were replaced
  };
  // ... other standard Ajv error properties
}

Configuration Requirements

ajv-errors has specific requirements for the Ajv instance:

  • allErrors must be true: Ajv must capture all validation errors for processing
  • jsPropertySyntax must be false: This Ajv option is incompatible with ajv-errors
  • Ajv version: Requires Ajv v8.0.1 or higher
// Correct Ajv configuration
const ajv = new Ajv({ 
  allErrors: true,           // Required
  jsPropertySyntax: false    // Required (or omit, false is default)
});

// This will throw an error
const badAjv = new Ajv({ allErrors: false });
ajvErrors(badAjv); // Error: "ajv-errors: Ajv option allErrors must be true"

Usage Examples

Basic Form Validation

import ajvErrors from "ajv-errors";
import Ajv from "ajv";

const ajv = new Ajv({ allErrors: true });
ajvErrors(ajv);

const userSchema = {
  type: "object",
  required: ["username", "email", "password"],
  properties: {
    username: { 
      type: "string", 
      minLength: 3, 
      maxLength: 20,
      pattern: "^[a-zA-Z0-9_]+$"
    },
    email: { 
      type: "string", 
      format: "email" 
    },
    password: { 
      type: "string", 
      minLength: 8 
    }
  },
  additionalProperties: false,
  errorMessage: {
    required: {
      username: "Username is required",
      email: "Email address is required", 
      password: "Password is required"
    },
    properties: {
      username: "Username must be 3-20 characters, letters/numbers/underscores only",
      email: "Please provide a valid email address",
      password: "Password must be at least 8 characters long"
    },
    additionalProperties: "Only username, email, and password are allowed"
  }
};

const validate = ajv.compile(userSchema);

API Response Validation with Templates

const productSchema = {
  type: "object",
  required: ["id", "name", "price"],
  properties: {
    id: { type: "string", pattern: "^prod_[0-9]+$" },
    name: { type: "string", minLength: 1 },
    price: { type: "number", minimum: 0 },
    category: { type: "string" }
  },
  errorMessage: {
    required: "Product missing required field: ${/missingProperty}",
    properties: {
      id: "Product ID '${/id}' must match format 'prod_123'",
      name: "Product name cannot be empty",
      price: "Price ${/price} must be a non-negative number"
    }
  }
};

Conditional Validation with Context

const conditionalSchema = {
  type: "object",
  properties: {
    type: { enum: ["personal", "business"] },
    taxId: { type: "string" }
  },
  if: { properties: { type: { const: "business" } } },
  then: { required: ["taxId"] },
  errorMessage: {
    if: "When type is 'business', taxId is required",
    _: "Invalid account configuration"
  }
};