0
# Error Handling
1
2
Comprehensive error reporting system with detailed validation failure information and customizable error handling. z-schema provides rich error information to help debug validation failures and implement custom error handling logic.
3
4
## Capabilities
5
6
### Get Last Error
7
8
Retrieve the most recent validation error as a structured Error object.
9
10
```javascript { .api }
11
/**
12
* Get the most recent validation error
13
* @returns Error object with validation details or null if validation succeeded
14
*/
15
getLastError(): ZSchema.SchemaError | null;
16
```
17
18
**Usage Examples:**
19
20
```javascript
21
const ZSchema = require("z-schema");
22
const validator = new ZSchema();
23
24
const schema = {
25
type: "object",
26
properties: {
27
name: { type: "string", minLength: 5 },
28
age: { type: "number", minimum: 18 }
29
},
30
required: ["name", "age"]
31
};
32
33
const data = { name: "Jo", age: 16 };
34
const valid = validator.validate(data, schema);
35
36
if (!valid) {
37
const error = validator.getLastError();
38
console.log("Error name:", error.name);
39
// Output: "z-schema validation error"
40
41
console.log("Error message:", error.message);
42
// Output: Summary message about validation failure
43
44
console.log("Error details:", error.details);
45
// Output: Array of detailed error information
46
47
// Use as standard Error object
48
throw error;
49
}
50
```
51
52
### Get Last Errors
53
54
Retrieve detailed array of all validation errors from the most recent validation.
55
56
```javascript { .api }
57
/**
58
* Get array of all validation errors from last validation
59
* @returns Array of error details or null if validation succeeded
60
*/
61
getLastErrors(): ZSchema.SchemaErrorDetail[] | null;
62
```
63
64
**Usage Examples:**
65
66
```javascript
67
const validator = new ZSchema();
68
69
const schema = {
70
type: "object",
71
properties: {
72
email: { type: "string", format: "email" },
73
age: { type: "number", minimum: 0, maximum: 120 },
74
tags: {
75
type: "array",
76
items: { type: "string" },
77
minItems: 1
78
}
79
},
80
required: ["email", "age"]
81
};
82
83
const invalidData = {
84
email: "not-an-email",
85
age: -5,
86
tags: []
87
};
88
89
const valid = validator.validate(invalidData, schema);
90
91
if (!valid) {
92
const errors = validator.getLastErrors();
93
94
errors.forEach((error, index) => {
95
console.log(`Error ${index + 1}:`);
96
console.log(` Code: ${error.code}`);
97
console.log(` Message: ${error.message}`);
98
console.log(` Path: ${error.path}`);
99
console.log(` Params:`, error.params);
100
101
if (error.inner && error.inner.length > 0) {
102
console.log(` Inner errors:`, error.inner.length);
103
}
104
});
105
106
/* Example output:
107
Error 1:
108
Code: INVALID_FORMAT
109
Message: Object didn't pass validation for format email: not-an-email
110
Path: #/email
111
Params: ["email", "not-an-email"]
112
113
Error 2:
114
Code: MINIMUM
115
Message: Value -5 is less than minimum 0
116
Path: #/age
117
Params: ["-5", "0"]
118
119
Error 3:
120
Code: ARRAY_LENGTH_SHORT
121
Message: Array is too short (0), minimum 1
122
Path: #/tags
123
Params: ["0", "1"]
124
*/
125
}
126
```
127
128
### Custom Error Handling
129
130
Implement custom error handling with detailed error analysis.
131
132
```javascript { .api }
133
// Error analysis helper functions
134
function analyzeValidationErrors(errors) {
135
const errorsByType = {};
136
const errorsByPath = {};
137
138
errors.forEach(error => {
139
// Group by error type
140
if (!errorsByType[error.code]) {
141
errorsByType[error.code] = [];
142
}
143
errorsByType[error.code].push(error);
144
145
// Group by path
146
if (!errorsByPath[error.path]) {
147
errorsByPath[error.path] = [];
148
}
149
errorsByPath[error.path].push(error);
150
});
151
152
return { errorsByType, errorsByPath };
153
}
154
```
155
156
**Usage Examples:**
157
158
```javascript
159
const validator = new ZSchema();
160
161
function validateWithCustomErrorHandling(data, schema) {
162
const valid = validator.validate(data, schema);
163
164
if (!valid) {
165
const errors = validator.getLastErrors();
166
const { errorsByType, errorsByPath } = analyzeValidationErrors(errors);
167
168
// Handle specific error types
169
if (errorsByType.INVALID_TYPE) {
170
console.log("Type validation errors found:");
171
errorsByType.INVALID_TYPE.forEach(error => {
172
console.log(` ${error.path}: expected ${error.params[0]}, got ${error.params[1]}`);
173
});
174
}
175
176
if (errorsByType.INVALID_FORMAT) {
177
console.log("Format validation errors found:");
178
errorsByType.INVALID_FORMAT.forEach(error => {
179
console.log(` ${error.path}: invalid ${error.params[0]} format`);
180
});
181
}
182
183
// Handle errors by field
184
Object.keys(errorsByPath).forEach(path => {
185
const fieldErrors = errorsByPath[path];
186
console.log(`Field ${path} has ${fieldErrors.length} error(s)`);
187
});
188
189
return {
190
valid: false,
191
errors: errors,
192
summary: {
193
totalErrors: errors.length,
194
errorTypes: Object.keys(errorsByType),
195
affectedFields: Object.keys(errorsByPath)
196
}
197
};
198
}
199
200
return { valid: true, errors: null, summary: null };
201
}
202
203
// Usage
204
const result = validateWithCustomErrorHandling(data, schema);
205
if (!result.valid) {
206
console.log("Validation summary:", result.summary);
207
}
208
```
209
210
### Custom Validator Function
211
212
Implement custom validation logic with error reporting.
213
214
```javascript { .api }
215
/**
216
* Custom validator function interface
217
* @param report - Report object for adding custom errors
218
* @param schema - Current schema being validated
219
* @param json - Current JSON data being validated
220
*/
221
interface CustomValidatorFunction {
222
(report: Report, schema: any, json: any): void;
223
}
224
225
interface Report {
226
/**
227
* Add custom error to validation report
228
* @param errorCode - Custom error code
229
* @param errorMessage - Error message template with {0}, {1} placeholders
230
* @param params - Array of parameters for message template
231
* @param subReports - Sub-schema reports (optional)
232
* @param schemaDescription - Schema description (optional)
233
*/
234
addCustomError(
235
errorCode: string,
236
errorMessage: string,
237
params: string[],
238
subReports?: any,
239
schemaDescription?: string
240
): void;
241
}
242
```
243
244
**Usage Examples:**
245
246
```javascript
247
// Custom validator for business logic
248
function businessRulesValidator(report, schema, json) {
249
// Custom validation: ensure unique properties
250
if (Array.isArray(schema.uniqueProperties)) {
251
const seenValues = [];
252
253
schema.uniqueProperties.forEach(prop => {
254
const value = json[prop];
255
if (typeof value !== "undefined") {
256
if (seenValues.indexOf(value) !== -1) {
257
report.addCustomError(
258
"NON_UNIQUE_PROPERTY_VALUE",
259
"Property '{0}' has non-unique value: {1}",
260
[prop, value.toString()],
261
null,
262
schema.description
263
);
264
}
265
seenValues.push(value);
266
}
267
});
268
}
269
270
// Custom validation: business date rules
271
if (schema.businessDateValidation && json.startDate && json.endDate) {
272
const start = new Date(json.startDate);
273
const end = new Date(json.endDate);
274
275
if (start >= end) {
276
report.addCustomError(
277
"INVALID_DATE_RANGE",
278
"Start date '{0}' must be before end date '{1}'",
279
[json.startDate, json.endDate],
280
null,
281
"Business rule: start date must precede end date"
282
);
283
}
284
285
const maxDuration = 365 * 24 * 60 * 60 * 1000; // 1 year in ms
286
if (end - start > maxDuration) {
287
report.addCustomError(
288
"DATE_RANGE_TOO_LONG",
289
"Date range cannot exceed 1 year: {0} to {1}",
290
[json.startDate, json.endDate]
291
);
292
}
293
}
294
}
295
296
// Use custom validator
297
const validator = new ZSchema({
298
customValidator: businessRulesValidator
299
});
300
301
const schema = {
302
type: "object",
303
properties: {
304
fromAccount: { type: "string" },
305
toAccount: { type: "string" },
306
startDate: { type: "string", format: "date" },
307
endDate: { type: "string", format: "date" }
308
},
309
uniqueProperties: ["fromAccount", "toAccount"],
310
businessDateValidation: true
311
};
312
313
// This will trigger custom validation errors
314
const invalidData = {
315
fromAccount: "12345",
316
toAccount: "12345", // Same as fromAccount - will trigger uniqueness error
317
startDate: "2023-12-01",
318
endDate: "2023-06-01" // Before startDate - will trigger date range error
319
};
320
321
const valid = validator.validate(invalidData, schema);
322
if (!valid) {
323
const errors = validator.getLastErrors();
324
errors.forEach(error => {
325
if (error.code.startsWith("NON_UNIQUE") || error.code.startsWith("INVALID_DATE")) {
326
console.log("Custom validation error:", error.message);
327
}
328
});
329
}
330
```
331
332
## Error Structure and Types
333
334
### Error Object Structure
335
336
```javascript { .api }
337
interface SchemaError extends Error {
338
/** Always "z-schema validation error" */
339
name: string;
340
341
/** Summary error message */
342
message: string;
343
344
/** Detailed error information array */
345
details: SchemaErrorDetail[];
346
}
347
348
interface SchemaErrorDetail {
349
/** Descriptive error message */
350
message: string;
351
352
/** Error code identifier */
353
code: string;
354
355
/** Parameters used in error message */
356
params: string[];
357
358
/** JSON path to the error location */
359
path: string;
360
361
/** Schema description (if available) */
362
description: string;
363
364
/** Nested errors for complex validation failures */
365
inner: SchemaErrorDetail[];
366
}
367
```
368
369
### Common Error Codes
370
371
```javascript { .api }
372
// Type validation errors
373
interface TypeErrors {
374
"INVALID_TYPE": "Expected type {0} but found type {1}";
375
"INVALID_FORMAT": "Object didn't pass validation for format {0}: {1}";
376
"ENUM_MISMATCH": "No enum match for: {0}";
377
"ENUM_CASE_MISMATCH": "Enum does not match case for: {0}";
378
}
379
380
// Composition validation errors
381
interface CompositionErrors {
382
"ANY_OF_MISSING": "Data does not match any schemas from 'anyOf'";
383
"ONE_OF_MISSING": "Data does not match any schemas from 'oneOf'";
384
"ONE_OF_MULTIPLE": "Data is valid against more than one schema from 'oneOf'";
385
"NOT_PASSED": "Data matches schema from 'not'";
386
}
387
388
// Array validation errors
389
interface ArrayErrors {
390
"ARRAY_LENGTH_SHORT": "Array is too short ({0}), minimum {1}";
391
"ARRAY_LENGTH_LONG": "Array is too long ({0}), maximum {1}";
392
"ARRAY_UNIQUE": "Array items are not unique (indexes {0} and {1})";
393
"ARRAY_ADDITIONAL_ITEMS": "Additional items not allowed";
394
}
395
396
// Numeric validation errors
397
interface NumericErrors {
398
"MULTIPLE_OF": "Value {0} is not a multiple of {1}";
399
"MINIMUM": "Value {0} is less than minimum {1}";
400
"MINIMUM_EXCLUSIVE": "Value {0} is equal or less than exclusive minimum {1}";
401
"MAXIMUM": "Value {0} is greater than maximum {1}";
402
"MAXIMUM_EXCLUSIVE": "Value {0} is equal or greater than exclusive maximum {1}";
403
}
404
405
// Object validation errors
406
interface ObjectErrors {
407
"OBJECT_PROPERTIES_MINIMUM": "Too few properties defined ({0}), minimum {1}";
408
"OBJECT_PROPERTIES_MAXIMUM": "Too many properties defined ({0}), maximum {1}";
409
"OBJECT_MISSING_REQUIRED_PROPERTY": "Missing required property: {0}";
410
"OBJECT_ADDITIONAL_PROPERTIES": "Additional properties not allowed: {0}";
411
"OBJECT_DEPENDENCY_KEY": "Dependency failed - key must exist: {0} (due to key: {1})";
412
}
413
414
// String validation errors
415
interface StringErrors {
416
"MIN_LENGTH": "String is too short ({0} chars), minimum {1}";
417
"MAX_LENGTH": "String is too long ({0} chars), maximum {1}";
418
"PATTERN": "String does not match pattern {0}: {1}";
419
}
420
421
// Schema and reference errors
422
interface SchemaErrors {
423
"UNRESOLVABLE_REFERENCE": "Reference could not be resolved: {0}";
424
"UNKNOWN_FORMAT": "There is no validation function for format '{0}'";
425
"ASYNC_TIMEOUT": "{0} asynchronous task(s) have timed out after {1} ms";
426
}
427
```
428
429
## Error Reporting Configuration
430
431
### Error Path Formatting
432
433
Control how error paths are reported in validation results.
434
435
```javascript { .api }
436
interface ErrorReportingOptions {
437
/** Report error paths as arrays instead of strings (default: false) */
438
reportPathAsArray?: boolean;
439
440
/** Stop after first error instead of collecting all errors (default: false) */
441
breakOnFirstError?: boolean;
442
}
443
```
444
445
**Usage Examples:**
446
447
```javascript
448
// String paths (default)
449
const validator1 = new ZSchema();
450
validator1.validate({ user: { name: 123 } }, schema);
451
const errors1 = validator1.getLastErrors();
452
console.log(errors1[0].path); // "#/user/name"
453
454
// Array paths
455
const validator2 = new ZSchema({ reportPathAsArray: true });
456
validator2.validate({ user: { name: 123 } }, schema);
457
const errors2 = validator2.getLastErrors();
458
console.log(errors2[0].path); // ["user", "name"]
459
460
// Fast-fail validation
461
const validator3 = new ZSchema({ breakOnFirstError: true });
462
validator3.validate(invalidData, schema);
463
const errors3 = validator3.getLastErrors();
464
console.log(errors3.length); // 1 (only first error)
465
```
466
467
### Selective Error Reporting
468
469
Validate only specific error types for performance optimization.
470
471
```javascript { .api }
472
interface SelectiveValidationOptions {
473
/** Only check for specific error types during validation */
474
includeErrors?: string[];
475
}
476
```
477
478
**Usage Examples:**
479
480
```javascript
481
const validator = new ZSchema();
482
483
// Only check for type errors
484
const valid = validator.validate(data, schema, {
485
includeErrors: ["INVALID_TYPE"]
486
});
487
488
// Only check for format and length errors
489
const valid2 = validator.validate(data, schema, {
490
includeErrors: ["INVALID_FORMAT", "MIN_LENGTH", "MAX_LENGTH"]
491
});
492
493
// Performance benefit: skips other validation checks
494
const valid3 = validator.validate(data, schema, {
495
includeErrors: ["OBJECT_MISSING_REQUIRED_PROPERTY"]
496
});
497
```