CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-ajv-errors

Custom error messages in JSON Schemas for Ajv validator

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

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"
  }
};
Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/ajv-errors@3.0.x
Publish Source
CLI
Badge
tessl/npm-ajv-errors badge