Merge pull request #1779 from pavel-pimenov/fix-1778-part-1

fix 1778  (part 1)
diff --git a/.gitignore b/.gitignore
index 1d3073f..5932e82 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@
 !/bin/encodings
 !/bin/jsonchecker
 !/bin/types
+!/bin/unittestschema
 /build
 /doc/html
 /doc/doxygen_*.db
diff --git a/bin/unittestschema/address.json b/bin/unittestschema/address.json
new file mode 100644
index 0000000..c3cf642
--- /dev/null
+++ b/bin/unittestschema/address.json
@@ -0,0 +1,139 @@
+{
+  "type": "object",
+  "properties": {
+    "version": {
+      "$ref": "#/definitions/decimal_type"
+    },
+    "address": {
+      "$ref": "#/definitions/address_type"
+    },
+    "phones": {
+      "type": "array",
+      "minItems": 1,
+      "maxItems": 2,
+      "uniqueItems": true,
+      "items": {
+        "$ref": "#/definitions/phone_type"
+      }
+    },
+    "names": {
+      "type": "array",
+      "items": [
+        { "type": "string" },
+        { "type": "string" }
+      ],
+      "additionalItems": false
+    },
+    "extra": {
+      "type": "object",
+      "patternProperties": {
+        "^S_": { "type": "string" }
+      }
+    },
+    "gender": {
+      "type": "string",
+      "enum": ["M", "F"]
+    }
+  },
+  "additionalProperties": false,
+  "dependencies": {
+    "address": [ "version" ],
+    "names": {
+      "properties": {
+        "version": { "$ref": "#/definitions/decimal_type" }
+      },
+      "required": ["version"]
+    }
+  },
+  "definitions": {
+    "address_type": {
+      "type": "object",
+      "properties": {
+        "number": {
+          "$ref": "#/definitions/positiveInt_type"
+        },
+        "street1": {
+          "type": "string"
+        },
+        "street2": {
+          "type": ["string", "null"]
+        },
+        "street3": {
+          "not": { "type": ["boolean", "number", ",integer", "object", "null"] }
+        },
+        "city": {
+          "type": "string",
+          "maxLength": 10,
+          "minLength": 4
+        },
+        "area": {
+          "oneOf": [
+            { "$ref": "#/definitions/county_type" },
+            { "$ref": "#/definitions/province_type" }
+          ]
+        },
+        "country": {
+          "allOf": [
+            { "$ref": "#/definitions/country_type" }
+          ]
+        },
+        "postcode": {
+          "anyOf": [
+            { "type": "string", "pattern": "^[A-Z]{2}[0-9]{1,2} [0-9][A-Z]{2}$" },
+            { "type": "string", "pattern": "^[0-9]{5}$" }
+          ]
+        }
+      },
+      "minProperties": 7,
+      "required": [
+        "number",
+        "street1",
+        "city"
+      ]
+    },
+    "country_type": {
+      "type": "string",
+      "enum": ["UK", "Canada"]
+    },
+    "county_type": {
+      "type": "string",
+      "enum": ["Sussex", "Surrey", "Kent"]
+    },
+    "province_type": {
+      "type": "string",
+      "enum": ["Quebec", "BC", "Alberta"]
+    },
+    "date_type": {
+      "pattern": "^([0-9]([0-9]([0-9][1-9]|[1-9]0)|[1-9]00)|[1-9]000)(-(0[1-9]|1[0-2])(-(0[1-9]|[1-2][0-9]|3[0-1]))?)?$",
+      "type": "string"
+    },
+    "positiveInt_type": {
+      "minimum": 0,
+      "exclusiveMinimum": true,
+      "maximum": 100,
+      "exclusiveMaximum": true,
+      "type": "integer"
+    },
+    "decimal_type": {
+      "multipleOf": 1.0,
+      "type": "number"
+    },
+    "time_type": {
+      "pattern": "^([01][0-9]|2[0-3]):[0-5][0-9]:([0-5][0-9]|60)(\\.[0-9]+)?$",
+      "type": "string"
+    },
+    "unsignedInt_type": {
+      "type": "integer",
+      "minimum": 0,
+      "maximum": 99999
+    },
+    "phone_type": {
+      "pattern": "^[0-9]*-[0-9]*",
+      "type": "string"
+    },
+    "url_type": {
+      "pattern": "^\\S*$",
+      "type": "string"
+    }
+  }
+}
\ No newline at end of file
diff --git a/bin/unittestschema/allOf_address.json b/bin/unittestschema/allOf_address.json
new file mode 100644
index 0000000..fd501f6
--- /dev/null
+++ b/bin/unittestschema/allOf_address.json
@@ -0,0 +1,7 @@
+{
+  "allOf": [
+    {
+      "$ref": "http://localhost:1234/address.json#"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/bin/unittestschema/anyOf_address.json b/bin/unittestschema/anyOf_address.json
new file mode 100644
index 0000000..5c90308
--- /dev/null
+++ b/bin/unittestschema/anyOf_address.json
@@ -0,0 +1,7 @@
+{
+  "anyOf": [
+    {
+      "$ref": "http://localhost:1234/address.json#"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/bin/unittestschema/oneOf_address.json b/bin/unittestschema/oneOf_address.json
new file mode 100644
index 0000000..a5baadd
--- /dev/null
+++ b/bin/unittestschema/oneOf_address.json
@@ -0,0 +1,7 @@
+{
+  "oneOf": [
+    {
+      "$ref": "http://localhost:1234/address.json#"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/example/schemavalidator/schemavalidator.cpp b/example/schemavalidator/schemavalidator.cpp
index 06bbe4d..bffd64a 100644
--- a/example/schemavalidator/schemavalidator.cpp
+++ b/example/schemavalidator/schemavalidator.cpp
@@ -7,9 +7,124 @@
 #include "rapidjson/schema.h"
 #include "rapidjson/stringbuffer.h"
 #include "rapidjson/prettywriter.h"
+#include <string>
+#include <iostream>
+#include <sstream>
 
 using namespace rapidjson;
 
+typedef GenericValue<UTF8<>, CrtAllocator > ValueType;
+
+// Forward ref
+static void CreateErrorMessages(const ValueType& errors, size_t depth, const char* context);
+
+// Convert GenericValue to std::string
+static std::string GetString(const ValueType& val) {
+  std::ostringstream s;
+  if (val.IsString())
+    s << val.GetString();
+  else if (val.IsDouble())
+    s << val.GetDouble();
+  else if (val.IsUint())
+   s << val.GetUint();
+  else if (val.IsInt())
+    s << val.GetInt();
+  else if (val.IsUint64())
+    s << val.GetUint64();
+  else if (val.IsInt64())
+    s <<  val.GetInt64();
+  else if (val.IsBool() && val.GetBool())
+    s << "true";
+  else if (val.IsBool())
+    s << "false";
+  else if (val.IsFloat())
+    s << val.GetFloat();
+  return s.str();}
+
+// Create the error message for a named error
+// The error object can either be empty or contain at least member properties:
+// {"errorCode": <code>, "instanceRef": "<pointer>", "schemaRef": "<pointer>" }
+// Additional properties may be present for use as inserts.
+// An "errors" property may be present if there are child errors.
+static void HandleError(const char* errorName, const ValueType& error, size_t depth, const char* context) {
+  if (!error.ObjectEmpty()) {
+    // Get error code and look up error message text (English)
+    int code = error["errorCode"].GetInt();
+    std::string message(GetValidateError_En(static_cast<ValidateErrorCode>(code)));
+    // For each member property in the error, see if its name exists as an insert in the error message and if so replace with the stringified property value
+    // So for example - "Number '%actual' is not a multiple of the 'multipleOf' value '%expected'." - we would expect "actual" and "expected" members.
+    for (ValueType::ConstMemberIterator insertsItr = error.MemberBegin();
+      insertsItr != error.MemberEnd(); ++insertsItr) {
+      std::string insertName("%");
+      insertName += insertsItr->name.GetString(); // eg "%actual"
+      size_t insertPos = message.find(insertName);
+      if (insertPos != std::string::npos) {
+        std::string insertString("");
+        const ValueType &insert = insertsItr->value;
+        if (insert.IsArray()) {
+          // Member is an array so create comma-separated list of items for the insert string
+          for (ValueType::ConstValueIterator itemsItr = insert.Begin(); itemsItr != insert.End(); ++itemsItr) {
+            if (itemsItr != insert.Begin()) insertString += ",";
+            insertString += GetString(*itemsItr);
+          }
+        } else {
+          insertString += GetString(insert);
+        }
+        message.replace(insertPos, insertName.length(), insertString);
+      }
+    }
+    // Output error message, references, context
+    std::string indent(depth * 2, ' ');
+    std::cout << indent << "Error Name: " << errorName << std::endl;
+    std::cout << indent << "Message: " << message.c_str() << std::endl;
+    std::cout << indent << "Instance: " << error["instanceRef"].GetString() << std::endl;
+    std::cout << indent << "Schema: " << error["schemaRef"].GetString() << std::endl;
+    if (depth > 0) std::cout << indent << "Context: " << context << std::endl;
+    std::cout << std::endl;
+
+    // If child errors exist, apply the process recursively to each error structure.
+    // This occurs for "oneOf", "allOf", "anyOf" and "dependencies" errors, so pass the error name as context.
+    if (error.HasMember("errors")) {
+      depth++;
+      const ValueType &childErrors = error["errors"];
+      if (childErrors.IsArray()) {
+        // Array - each item is an error structure - example
+        // "anyOf": {"errorCode": ..., "errors":[{"pattern": {"errorCode\": ...\"}}, {"pattern": {"errorCode\": ...}}]
+        for (ValueType::ConstValueIterator errorsItr = childErrors.Begin();
+             errorsItr != childErrors.End(); ++errorsItr) {
+          CreateErrorMessages(*errorsItr, depth, errorName);
+        }
+      } else if (childErrors.IsObject()) {
+        // Object - each member is an error structure - example
+        // "dependencies": {"errorCode": ..., "errors": {"address": {"required": {"errorCode": ...}}, "name": {"required": {"errorCode": ...}}}
+        for (ValueType::ConstMemberIterator propsItr = childErrors.MemberBegin();
+             propsItr != childErrors.MemberEnd(); ++propsItr) {
+          CreateErrorMessages(propsItr->value, depth, errorName);
+        }
+      }
+    }
+  }
+}
+
+// Create error message for all errors in an error structure
+// Context is used to indicate whether the error structure has a parent 'dependencies', 'allOf', 'anyOf' or 'oneOf' error
+static void CreateErrorMessages(const ValueType& errors, size_t depth = 0, const char* context = 0) {
+    // Each member property contains one or more errors of a given type
+    for (ValueType::ConstMemberIterator errorTypeItr = errors.MemberBegin(); errorTypeItr != errors.MemberEnd(); ++errorTypeItr) {
+        const char* errorName = errorTypeItr->name.GetString();
+        const ValueType& errorContent = errorTypeItr->value;
+        if (errorContent.IsArray()) {
+            // Member is an array where each item is an error - eg "type": [{"errorCode": ...}, {"errorCode": ...}]
+            for (ValueType::ConstValueIterator contentItr = errorContent.Begin(); contentItr != errorContent.End(); ++contentItr) {
+                HandleError(errorName, *contentItr, depth, context);
+            }
+        } else if (errorContent.IsObject()) {
+            // Member is an object which is a single error - eg "type": {"errorCode": ... }
+            HandleError(errorName, errorContent, depth, context);
+        }
+    }
+}
+
 int main(int argc, char *argv[]) {
     if (argc != 2) {
         fprintf(stderr, "Usage: schemavalidator schema.json < input.json\n");
@@ -65,6 +180,8 @@
         validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
         fprintf(stderr, "Invalid schema: %s\n", sb.GetString());
         fprintf(stderr, "Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());
+        fprintf(stderr, "Invalid code: %d\n", validator.GetInvalidSchemaCode());
+        fprintf(stderr, "Invalid message: %s\n", GetValidateError_En(validator.GetInvalidSchemaCode()));
         sb.Clear();
         validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
         fprintf(stderr, "Invalid document: %s\n", sb.GetString());
@@ -73,6 +190,7 @@
         PrettyWriter<StringBuffer> w(sb);
         validator.GetError().Accept(w);
         fprintf(stderr, "Error report:\n%s\n", sb.GetString());
+        CreateErrorMessages(validator.GetError());
         return EXIT_FAILURE;
     }
 }
diff --git a/include/rapidjson/allocators.h b/include/rapidjson/allocators.h
index 0b8f5e1..44ec529 100644
--- a/include/rapidjson/allocators.h
+++ b/include/rapidjson/allocators.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/cursorstreamwrapper.h b/include/rapidjson/cursorstreamwrapper.h
index 52c11a7..fd6513d 100644
--- a/include/rapidjson/cursorstreamwrapper.h
+++ b/include/rapidjson/cursorstreamwrapper.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 //
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h
index 68aaae7..0910122 100644
--- a/include/rapidjson/document.h
+++ b/include/rapidjson/document.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
@@ -289,12 +289,14 @@
 //! non-const GenericMemberIterator
 template <typename Encoding, typename Allocator>
 class GenericMemberIterator<false,Encoding,Allocator> {
+public:
     //! use plain pointer as iterator type
     typedef GenericMember<Encoding,Allocator>* Iterator;
 };
 //! const GenericMemberIterator
 template <typename Encoding, typename Allocator>
 class GenericMemberIterator<true,Encoding,Allocator> {
+public:
     //! use plain const pointer as iterator type
     typedef const GenericMember<Encoding,Allocator>* Iterator;
 };
@@ -1081,6 +1083,7 @@
      */
     template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); }
 
+#ifndef __cpp_lib_three_way_comparison
     //! Equal-to operator with arbitrary types (symmetric version)
     /*! \return (rhs == lhs)
      */
@@ -1091,6 +1094,7 @@
      */
     template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); }
     //@}
+#endif
 
     //!@name Type
     //@{
@@ -2001,17 +2005,18 @@
 
         // Initial flags of different types.
         kNullFlag = kNullType,
-        kTrueFlag = kTrueType | kBoolFlag,
-        kFalseFlag = kFalseType | kBoolFlag,
-        kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag,
-        kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag,
-        kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag,
-        kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag,
-        kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag,
-        kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag,
-        kConstStringFlag = kStringType | kStringFlag,
-        kCopyStringFlag = kStringType | kStringFlag | kCopyFlag,
-        kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFlag,
+        // These casts are added to suppress the warning on MSVC about bitwise operations between enums of different types.
+        kTrueFlag = static_cast<int>(kTrueType) | static_cast<int>(kBoolFlag),
+        kFalseFlag = static_cast<int>(kFalseType) | static_cast<int>(kBoolFlag),
+        kNumberIntFlag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kIntFlag | kInt64Flag),
+        kNumberUintFlag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag),
+        kNumberInt64Flag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kInt64Flag),
+        kNumberUint64Flag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kUint64Flag),
+        kNumberDoubleFlag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kDoubleFlag),
+        kNumberAnyFlag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag),
+        kConstStringFlag = static_cast<int>(kStringType) | static_cast<int>(kStringFlag),
+        kCopyStringFlag = static_cast<int>(kStringType) | static_cast<int>(kStringFlag | kCopyFlag),
+        kShortStringFlag = static_cast<int>(kStringType) | static_cast<int>(kStringFlag | kCopyFlag | kInlineStrFlag),
         kObjectFlag = kObjectType,
         kArrayFlag = kArrayType,
 
@@ -2609,6 +2614,7 @@
     GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; return *this; }
     ~GenericArray() {}
 
+    operator ValueType&() const { return value_; }
     SizeType Size() const { return value_.Size(); }
     SizeType Capacity() const { return value_.Capacity(); }
     bool Empty() const { return value_.Empty(); }
@@ -2664,6 +2670,7 @@
     GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; return *this; }
     ~GenericObject() {}
 
+    operator ValueType&() const { return value_; }
     SizeType MemberCount() const { return value_.MemberCount(); }
     SizeType MemberCapacity() const { return value_.MemberCapacity(); }
     bool ObjectEmpty() const { return value_.ObjectEmpty(); }
diff --git a/include/rapidjson/encodedstream.h b/include/rapidjson/encodedstream.h
index 223601c..cf046b8 100644
--- a/include/rapidjson/encodedstream.h
+++ b/include/rapidjson/encodedstream.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/encodings.h b/include/rapidjson/encodings.h
index 0b24467..50ad18b 100644
--- a/include/rapidjson/encodings.h
+++ b/include/rapidjson/encodings.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/error/en.h b/include/rapidjson/error/en.h
index 2db838b..5d2e57b 100644
--- a/include/rapidjson/error/en.h
+++ b/include/rapidjson/error/en.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
@@ -65,6 +65,54 @@
     }
 }
 
+//! Maps error code of validation into error message.
+/*!
+    \ingroup RAPIDJSON_ERRORS
+    \param validateErrorCode Error code obtained from validator.
+    \return the error message.
+    \note User can make a copy of this function for localization.
+        Using switch-case is safer for future modification of error codes.
+*/
+inline const RAPIDJSON_ERROR_CHARTYPE* GetValidateError_En(ValidateErrorCode validateErrorCode) {
+    switch (validateErrorCode) {
+        case kValidateErrors:                           return RAPIDJSON_ERROR_STRING("One or more validation errors have occurred");
+        case kValidateErrorNone:                        return RAPIDJSON_ERROR_STRING("No error.");
+
+        case kValidateErrorMultipleOf:                  return RAPIDJSON_ERROR_STRING("Number '%actual' is not a multiple of the 'multipleOf' value '%expected'.");
+        case kValidateErrorMaximum:                     return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than the 'maximum' value '%expected'.");
+        case kValidateErrorExclusiveMaximum:            return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than or equal to the 'exclusiveMaximum' value '%expected'.");
+        case kValidateErrorMinimum:                     return RAPIDJSON_ERROR_STRING("Number '%actual' is less than the 'minimum' value '%expected'.");
+        case kValidateErrorExclusiveMinimum:            return RAPIDJSON_ERROR_STRING("Number '%actual' is less than or equal to the 'exclusiveMinimum' value '%expected'.");
+
+        case kValidateErrorMaxLength:                   return RAPIDJSON_ERROR_STRING("String '%actual' is longer than the 'maxLength' value '%expected'.");
+        case kValidateErrorMinLength:                   return RAPIDJSON_ERROR_STRING("String '%actual' is shorter than the 'minLength' value '%expected'.");
+        case kValidateErrorPattern:                     return RAPIDJSON_ERROR_STRING("String '%actual' does not match the 'pattern' regular expression.");
+
+        case kValidateErrorMaxItems:                    return RAPIDJSON_ERROR_STRING("Array of length '%actual' is longer than the 'maxItems' value '%expected'.");
+        case kValidateErrorMinItems:                    return RAPIDJSON_ERROR_STRING("Array of length '%actual' is shorter than the 'minItems' value '%expected'.");
+        case kValidateErrorUniqueItems:                 return RAPIDJSON_ERROR_STRING("Array has duplicate items at indices '%duplicates' but 'uniqueItems' is true.");
+        case kValidateErrorAdditionalItems:             return RAPIDJSON_ERROR_STRING("Array has an additional item at index '%disallowed' that is not allowed by the schema.");
+
+        case kValidateErrorMaxProperties:               return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is more than 'maxProperties' value '%expected'.");
+        case kValidateErrorMinProperties:               return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is less than 'minProperties' value '%expected'.");
+        case kValidateErrorRequired:                    return RAPIDJSON_ERROR_STRING("Object is missing the following members required by the schema: '%missing'.");
+        case kValidateErrorAdditionalProperties:        return RAPIDJSON_ERROR_STRING("Object has an additional member '%disallowed' that is not allowed by the schema.");
+        case kValidateErrorPatternProperties:           return RAPIDJSON_ERROR_STRING("Object has 'patternProperties' that are not allowed by the schema.");
+        case kValidateErrorDependencies:                return RAPIDJSON_ERROR_STRING("Object has missing property or schema dependencies, refer to following errors.");
+
+        case kValidateErrorEnum:                        return RAPIDJSON_ERROR_STRING("Property has a value that is not one of its allowed enumerated values.");
+        case kValidateErrorType:                        return RAPIDJSON_ERROR_STRING("Property has a type '%actual' that is not in the following list: '%expected'.");
+
+        case kValidateErrorOneOf:                       return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'oneOf', refer to following errors.");
+        case kValidateErrorOneOfMatch:                  return RAPIDJSON_ERROR_STRING("Property matched more than one of the sub-schemas specified by 'oneOf'.");
+        case kValidateErrorAllOf:                       return RAPIDJSON_ERROR_STRING("Property did not match all of the sub-schemas specified by 'allOf', refer to following errors.");
+        case kValidateErrorAnyOf:                       return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'anyOf', refer to following errors.");
+        case kValidateErrorNot:                         return RAPIDJSON_ERROR_STRING("Property matched the sub-schema specified by 'not'.");
+
+        default:                                        return RAPIDJSON_ERROR_STRING("Unknown error.");
+    }
+}
+
 RAPIDJSON_NAMESPACE_END
 
 #ifdef __clang__
diff --git a/include/rapidjson/error/error.h b/include/rapidjson/error/error.h
index 9311d2f..6270da1 100644
--- a/include/rapidjson/error/error.h
+++ b/include/rapidjson/error/error.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
@@ -152,6 +152,61 @@
 */
 typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
 
+///////////////////////////////////////////////////////////////////////////////
+// ValidateErrorCode
+
+//! Error codes when validating.
+/*! \ingroup RAPIDJSON_ERRORS
+    \see GenericSchemaValidator
+*/
+enum ValidateErrorCode {
+    kValidateErrors    = -1,                   //!< Top level error code when kValidateContinueOnErrorsFlag set.
+    kValidateErrorNone = 0,                    //!< No error.
+
+    kValidateErrorMultipleOf,                  //!< Number is not a multiple of the 'multipleOf' value.
+    kValidateErrorMaximum,                     //!< Number is greater than the 'maximum' value.
+    kValidateErrorExclusiveMaximum,            //!< Number is greater than or equal to the 'maximum' value.
+    kValidateErrorMinimum,                     //!< Number is less than the 'minimum' value.
+    kValidateErrorExclusiveMinimum,            //!< Number is less than or equal to the 'minimum' value.
+
+    kValidateErrorMaxLength,                   //!< String is longer than the 'maxLength' value.
+    kValidateErrorMinLength,                   //!< String is longer than the 'maxLength' value.
+    kValidateErrorPattern,                     //!< String does not match the 'pattern' regular expression.
+
+    kValidateErrorMaxItems,                    //!< Array is longer than the 'maxItems' value.
+    kValidateErrorMinItems,                    //!< Array is shorter than the 'minItems' value.
+    kValidateErrorUniqueItems,                 //!< Array has duplicate items but 'uniqueItems' is true.
+    kValidateErrorAdditionalItems,             //!< Array has additional items that are not allowed by the schema.
+
+    kValidateErrorMaxProperties,               //!< Object has more members than 'maxProperties' value.
+    kValidateErrorMinProperties,               //!< Object has less members than 'minProperties' value.
+    kValidateErrorRequired,                    //!< Object is missing one or more members required by the schema.
+    kValidateErrorAdditionalProperties,        //!< Object has additional members that are not allowed by the schema.
+    kValidateErrorPatternProperties,           //!< See other errors.
+    kValidateErrorDependencies,                //!< Object has missing property or schema dependencies.
+
+    kValidateErrorEnum,                        //!< Property has a value that is not one of its allowed enumerated values
+    kValidateErrorType,                        //!< Property has a type that is not allowed by the schema..
+
+    kValidateErrorOneOf,                       //!< Property did not match any of the sub-schemas specified by 'oneOf'.
+    kValidateErrorOneOfMatch,                  //!< Property matched more than one of the sub-schemas specified by 'oneOf'.
+    kValidateErrorAllOf,                       //!< Property did not match all of the sub-schemas specified by 'allOf'.
+    kValidateErrorAnyOf,                       //!< Property did not match any of the sub-schemas specified by 'anyOf'.
+    kValidateErrorNot                          //!< Property matched the sub-schema specified by 'not'.
+};
+
+//! Function pointer type of GetValidateError().
+/*! \ingroup RAPIDJSON_ERRORS
+
+    This is the prototype for \c GetValidateError_X(), where \c X is a locale.
+    User can dynamically change locale in runtime, e.g.:
+\code
+    GetValidateErrorFunc GetValidateError = GetValidateError_En; // or whatever
+    const RAPIDJSON_ERROR_CHARTYPE* s = GetValidateError(validator.GetInvalidSchemaCode());
+\endcode
+*/
+typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetValidateErrorFunc)(ValidateErrorCode);
+
 RAPIDJSON_NAMESPACE_END
 
 #ifdef __clang__
diff --git a/include/rapidjson/filereadstream.h b/include/rapidjson/filereadstream.h
index 6b34370..f8bb43c 100644
--- a/include/rapidjson/filereadstream.h
+++ b/include/rapidjson/filereadstream.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/filewritestream.h b/include/rapidjson/filewritestream.h
index 8b48fee..5d89588 100644
--- a/include/rapidjson/filewritestream.h
+++ b/include/rapidjson/filewritestream.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/fwd.h b/include/rapidjson/fwd.h
index b74a2b8..d62f77f 100644
--- a/include/rapidjson/fwd.h
+++ b/include/rapidjson/fwd.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/internal/biginteger.h b/include/rapidjson/internal/biginteger.h
index 8eb87c7..1245578 100644
--- a/include/rapidjson/internal/biginteger.h
+++ b/include/rapidjson/internal/biginteger.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/internal/clzll.h b/include/rapidjson/internal/clzll.h
index 47bb7ab..8fc5118 100644
--- a/include/rapidjson/internal/clzll.h
+++ b/include/rapidjson/internal/clzll.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 //
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/internal/diyfp.h b/include/rapidjson/internal/diyfp.h
index 8f7d853..a40797e 100644
--- a/include/rapidjson/internal/diyfp.h
+++ b/include/rapidjson/internal/diyfp.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 //
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/internal/dtoa.h b/include/rapidjson/internal/dtoa.h
index bf2e9b2..621402f 100644
--- a/include/rapidjson/internal/dtoa.h
+++ b/include/rapidjson/internal/dtoa.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/internal/ieee754.h b/include/rapidjson/internal/ieee754.h
index c2684ba..68c9e96 100644
--- a/include/rapidjson/internal/ieee754.h
+++ b/include/rapidjson/internal/ieee754.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/internal/itoa.h b/include/rapidjson/internal/itoa.h
index 9b1c45c..9fe8c93 100644
--- a/include/rapidjson/internal/itoa.h
+++ b/include/rapidjson/internal/itoa.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 //
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/internal/meta.h b/include/rapidjson/internal/meta.h
index d401edf..27092dc 100644
--- a/include/rapidjson/internal/meta.h
+++ b/include/rapidjson/internal/meta.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/internal/pow10.h b/include/rapidjson/internal/pow10.h
index 02f475d..eae1a43 100644
--- a/include/rapidjson/internal/pow10.h
+++ b/include/rapidjson/internal/pow10.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/internal/regex.h b/include/rapidjson/internal/regex.h
index af7e06d..6446c40 100644
--- a/include/rapidjson/internal/regex.h
+++ b/include/rapidjson/internal/regex.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/internal/stack.h b/include/rapidjson/internal/stack.h
index 45dca6a..73abd70 100644
--- a/include/rapidjson/internal/stack.h
+++ b/include/rapidjson/internal/stack.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/internal/strfunc.h b/include/rapidjson/internal/strfunc.h
index 226439a..baecb6c 100644
--- a/include/rapidjson/internal/strfunc.h
+++ b/include/rapidjson/internal/strfunc.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/internal/strtod.h b/include/rapidjson/internal/strtod.h
index dfca22b..d61a67a 100644
--- a/include/rapidjson/internal/strtod.h
+++ b/include/rapidjson/internal/strtod.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/internal/swap.h b/include/rapidjson/internal/swap.h
index 666e49f..2cf92f9 100644
--- a/include/rapidjson/internal/swap.h
+++ b/include/rapidjson/internal/swap.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 //
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/istreamwrapper.h b/include/rapidjson/istreamwrapper.h
index c4950b9..01437ec 100644
--- a/include/rapidjson/istreamwrapper.h
+++ b/include/rapidjson/istreamwrapper.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/memorybuffer.h b/include/rapidjson/memorybuffer.h
index 39bee1d..ffbc41e 100644
--- a/include/rapidjson/memorybuffer.h
+++ b/include/rapidjson/memorybuffer.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/memorystream.h b/include/rapidjson/memorystream.h
index 1d71d8a..77af6c9 100644
--- a/include/rapidjson/memorystream.h
+++ b/include/rapidjson/memorystream.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/ostreamwrapper.h b/include/rapidjson/ostreamwrapper.h
index 6f4667c..11ed4d3 100644
--- a/include/rapidjson/ostreamwrapper.h
+++ b/include/rapidjson/ostreamwrapper.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/pointer.h b/include/rapidjson/pointer.h
index b8143b6..90e5903 100644
--- a/include/rapidjson/pointer.h
+++ b/include/rapidjson/pointer.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/prettywriter.h b/include/rapidjson/prettywriter.h
index 94eeb69..fe45df1 100644
--- a/include/rapidjson/prettywriter.h
+++ b/include/rapidjson/prettywriter.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h
index c5f4d65..78aa89a 100644
--- a/include/rapidjson/rapidjson.h
+++ b/include/rapidjson/rapidjson.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h
index 30e45e1..09ace4e 100644
--- a/include/rapidjson/reader.h
+++ b/include/rapidjson/reader.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 //
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h
index 4e5f217..a034021 100644
--- a/include/rapidjson/schema.h
+++ b/include/rapidjson/schema.h
@@ -18,6 +18,7 @@
 #include "document.h"
 #include "pointer.h"
 #include "stringbuffer.h"
+#include "error/en.h"
 #include <cmath> // abs, floor
 
 #if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)
@@ -113,14 +114,37 @@
 #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword)
 #endif
 
-#define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\
+#define RAPIDJSON_INVALID_KEYWORD_RETURN(code)\
 RAPIDJSON_MULTILINEMACRO_BEGIN\
-    context.invalidKeyword = keyword.GetString();\
-    RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\
+    context.invalidCode = code;\
+    context.invalidKeyword = SchemaType::GetValidateErrorKeyword(code).GetString();\
+    RAPIDJSON_INVALID_KEYWORD_VERBOSE(context.invalidKeyword);\
     return false;\
 RAPIDJSON_MULTILINEMACRO_END
 
 ///////////////////////////////////////////////////////////////////////////////
+// ValidateFlag
+
+/*! \def RAPIDJSON_VALIDATE_DEFAULT_FLAGS
+    \ingroup RAPIDJSON_CONFIG
+    \brief User-defined kValidateDefaultFlags definition.
+
+    User can define this as any \c ValidateFlag combinations.
+*/
+#ifndef RAPIDJSON_VALIDATE_DEFAULT_FLAGS
+#define RAPIDJSON_VALIDATE_DEFAULT_FLAGS kValidateNoFlags
+#endif
+
+//! Combination of validate flags
+/*! \see
+ */
+enum ValidateFlag {
+    kValidateNoFlags = 0,                                       //!< No flags are set.
+    kValidateContinueOnErrorFlag = 1,                           //!< Don't stop after first validation error.
+    kValidateDefaultFlags = RAPIDJSON_VALIDATE_DEFAULT_FLAGS    //!< Default validate flags. Can be customized by defining RAPIDJSON_VALIDATE_DEFAULT_FLAGS
+};
+
+///////////////////////////////////////////////////////////////////////////////
 // Forward declarations
 
 template <typename ValueType, typename Allocator>
@@ -138,6 +162,8 @@
 public:
     virtual ~ISchemaValidator() {}
     virtual bool IsValid() const = 0;
+    virtual void SetValidateFlags(unsigned flags) = 0;
+    virtual unsigned GetValidateFlags() const = 0;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -147,7 +173,7 @@
 class ISchemaStateFactory {
 public:
     virtual ~ISchemaStateFactory() {}
-    virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&) = 0;
+    virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&, const bool inheritContinueOnErrors) = 0;
     virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0;
     virtual void* CreateHasher() = 0;
     virtual uint64_t GetHashCode(void* hasher) = 0;
@@ -201,13 +227,13 @@
     virtual void AddDependencySchemaError(const SValue& souceName, ISchemaValidator* subvalidator) = 0;
     virtual bool EndDependencyErrors() = 0;
 
-    virtual void DisallowedValue() = 0;
+    virtual void DisallowedValue(const ValidateErrorCode code) = 0;
     virtual void StartDisallowedType() = 0;
     virtual void AddExpectedType(const typename SchemaType::ValueType& expectedType) = 0;
     virtual void EndDisallowedType(const typename SchemaType::ValueType& actualType) = 0;
     virtual void NotAllOf(ISchemaValidator** subvalidators, SizeType count) = 0;
     virtual void NoneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
-    virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
+    virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count, bool matched) = 0;
     virtual void Disallowed() = 0;
 };
 
@@ -332,6 +358,7 @@
         schema(s),
         valueSchema(),
         invalidKeyword(),
+        invalidCode(),
         hasher(),
         arrayElementHashCodes(),
         validators(),
@@ -372,6 +399,7 @@
     const SchemaType* schema;
     const SchemaType* valueSchema;
     const Ch* invalidKeyword;
+    ValidateErrorCode invalidCode;
     void* hasher; // Only validator access
     void* arrayElementHashCodes; // Only validator access this
     ISchemaValidator** validators;
@@ -458,7 +486,7 @@
                     AddType(*itr);
         }
 
-        if (const ValueType* v = GetMember(value, GetEnumString()))
+        if (const ValueType* v = GetMember(value, GetEnumString())) {
             if (v->IsArray() && v->Size() > 0) {
                 enum_ = static_cast<uint64_t*>(allocator_->Malloc(sizeof(uint64_t) * v->Size()));
                 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
@@ -470,6 +498,7 @@
                     enum_[enumCount_++] = h.GetHashCode();
                 }
             }
+        }
 
         if (schemaDocument) {
             AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);
@@ -688,7 +717,11 @@
                     context.valueSchema = typeless_;
                 else {
                     context.error_handler.DisallowedItem(context.arrayElementIndex);
-                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString());
+                    // Must set valueSchema for when kValidateContinueOnErrorFlag is set, else reports spurious type error
+                    context.valueSchema = typeless_;
+                    // Must bump arrayElementIndex for when kValidateContinueOnErrorFlag is set
+                    context.arrayElementIndex++;
+                    RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAdditionalItems);
                 }
             }
             else
@@ -700,6 +733,7 @@
     }
 
     RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const {
+        // Only check pattern properties if we have validators
         if (context.patternPropertiesValidatorCount > 0) {
             bool otherValid = false;
             SizeType count = context.patternPropertiesValidatorCount;
@@ -716,66 +750,70 @@
             if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) {
                 if (!patternValid) {
                     context.error_handler.PropertyViolations(context.patternPropertiesValidators, count);
-                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
+                    RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties);
                 }
             }
             else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) {
                 if (!patternValid || !otherValid) {
                     context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
-                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
+                    RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties);
                 }
             }
             else if (!patternValid && !otherValid) { // kPatternValidatorWithAdditionalProperty)
                 context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
-                RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
+                RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties);
             }
         }
 
-        if (enum_) {
+        // For enums only check if we have a hasher
+        if (enum_ && context.hasher) {
             const uint64_t h = context.factory.GetHashCode(context.hasher);
             for (SizeType i = 0; i < enumCount_; i++)
                 if (enum_[i] == h)
                     goto foundEnum;
-            context.error_handler.DisallowedValue();
-            RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString());
+            context.error_handler.DisallowedValue(kValidateErrorEnum);
+            RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorEnum);
             foundEnum:;
         }
 
-        if (allOf_.schemas)
-            for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
-                if (!context.validators[i]->IsValid()) {
-                    context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count);
-                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString());
-                }
-        
-        if (anyOf_.schemas) {
-            for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
-                if (context.validators[i]->IsValid())
-                    goto foundAny;
-            context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count);
-            RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString());
-            foundAny:;
-        }
+    // Only check allOf etc if we have validators
+        if (context.validatorCount > 0) {
+            if (allOf_.schemas)
+                for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
+                    if (!context.validators[i]->IsValid()) {
+                        context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count);
+                        RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAllOf);
+                    }
 
-        if (oneOf_.schemas) {
-            bool oneValid = false;
-            for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
-                if (context.validators[i]->IsValid()) {
-                    if (oneValid) {
-                        context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count);
-                        RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
-                    } else
-                        oneValid = true;
-                }
-            if (!oneValid) {
-                context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count);
-                RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
+            if (anyOf_.schemas) {
+                for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
+                    if (context.validators[i]->IsValid())
+                        goto foundAny;
+                context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count);
+                RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAnyOf);
+                foundAny:;
             }
-        }
 
-        if (not_ && context.validators[notValidatorIndex_]->IsValid()) {
-            context.error_handler.Disallowed();
-            RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString());
+            if (oneOf_.schemas) {
+                bool oneValid = false;
+                for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
+                    if (context.validators[i]->IsValid()) {
+                        if (oneValid) {
+                            context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count, true);
+                            RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOfMatch);
+                        } else
+                            oneValid = true;
+                    }
+                if (!oneValid) {
+                    context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count, false);
+                    RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOf);
+                }
+            }
+
+            if (not_ && context.validators[notValidatorIndex_]->IsValid()) {
+                context.error_handler.Disallowed();
+                RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorNot);
+            }
         }
 
         return true;
@@ -784,7 +822,7 @@
     bool Null(Context& context) const {
         if (!(type_ & (1 << kNullSchemaType))) {
             DisallowedType(context, GetNullString());
-            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+            RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
         }
         return CreateParallelValidator(context);
     }
@@ -792,7 +830,7 @@
     bool Bool(Context& context, bool) const {
         if (!(type_ & (1 << kBooleanSchemaType))) {
             DisallowedType(context, GetBooleanString());
-            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+            RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
         }
         return CreateParallelValidator(context);
     }
@@ -824,7 +862,7 @@
     bool Double(Context& context, double d) const {
         if (!(type_ & (1 << kNumberSchemaType))) {
             DisallowedType(context, GetNumberString());
-            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+            RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
         }
 
         if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
@@ -842,7 +880,7 @@
     bool String(Context& context, const Ch* str, SizeType length, bool) const {
         if (!(type_ & (1 << kStringSchemaType))) {
             DisallowedType(context, GetStringString());
-            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+            RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
         }
 
         if (minLength_ != 0 || maxLength_ != SizeType(~0)) {
@@ -850,18 +888,18 @@
             if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {
                 if (count < minLength_) {
                     context.error_handler.TooShort(str, length, minLength_);
-                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString());
+                    RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinLength);
                 }
                 if (count > maxLength_) {
                     context.error_handler.TooLong(str, length, maxLength_);
-                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString());
+                    RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxLength);
                 }
             }
         }
 
         if (pattern_ && !IsPatternMatch(pattern_, str, length)) {
             context.error_handler.DoesNotMatch(str, length);
-            RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString());
+            RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPattern);
         }
 
         return CreateParallelValidator(context);
@@ -870,7 +908,7 @@
     bool StartObject(Context& context) const {
         if (!(type_ & (1 << kObjectSchemaType))) {
             DisallowedType(context, GetObjectString());
-            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+            RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
         }
 
         if (hasDependencies_ || hasRequired_) {
@@ -930,8 +968,10 @@
         }
 
         if (context.patternPropertiesSchemaCount == 0) { // patternProperties are not additional properties
+            // Must set valueSchema for when kValidateContinueOnErrorFlag is set, else reports spurious type error
+            context.valueSchema = typeless_;
             context.error_handler.DisallowedProperty(str, len);
-            RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString());
+            RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAdditionalProperties);
         }
 
         return true;
@@ -945,17 +985,17 @@
                     if (properties_[index].schema->defaultValueLength_ == 0 )
                         context.error_handler.AddMissingProperty(properties_[index].name);
             if (context.error_handler.EndMissingProperties())
-                RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString());
+                RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorRequired);
         }
 
         if (memberCount < minProperties_) {
             context.error_handler.TooFewProperties(memberCount, minProperties_);
-            RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString());
+            RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinProperties);
         }
 
         if (memberCount > maxProperties_) {
             context.error_handler.TooManyProperties(memberCount, maxProperties_);
-            RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString());
+            RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxProperties);
         }
 
         if (hasDependencies_) {
@@ -978,21 +1018,21 @@
                 }
             }
             if (context.error_handler.EndDependencyErrors())
-                RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
+                RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorDependencies);  
         }
 
         return true;
     }
 
     bool StartArray(Context& context) const {
+        context.arrayElementIndex = 0;
+        context.inArray = true;  // Ensure we note that we are in an array
+
         if (!(type_ & (1 << kArraySchemaType))) {
             DisallowedType(context, GetArrayString());
-            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+            RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
         }
 
-        context.arrayElementIndex = 0;
-        context.inArray = true;
-
         return CreateParallelValidator(context);
     }
 
@@ -1001,17 +1041,55 @@
         
         if (elementCount < minItems_) {
             context.error_handler.TooFewItems(elementCount, minItems_);
-            RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString());
+            RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinItems);
         }
         
         if (elementCount > maxItems_) {
             context.error_handler.TooManyItems(elementCount, maxItems_);
-            RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString());
+            RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxItems);
         }
 
         return true;
     }
 
+    static const ValueType& GetValidateErrorKeyword(ValidateErrorCode validateErrorCode) {
+        switch (validateErrorCode) {
+            case kValidateErrorMultipleOf:              return GetMultipleOfString();
+            case kValidateErrorMaximum:                 return GetMaximumString();
+            case kValidateErrorExclusiveMaximum:        return GetMaximumString(); // Same
+            case kValidateErrorMinimum:                 return GetMinimumString();
+            case kValidateErrorExclusiveMinimum:        return GetMinimumString(); // Same
+
+            case kValidateErrorMaxLength:               return GetMaxLengthString();
+            case kValidateErrorMinLength:               return GetMinLengthString();
+            case kValidateErrorPattern:                 return GetPatternString();
+
+            case kValidateErrorMaxItems:                return GetMaxItemsString();
+            case kValidateErrorMinItems:                return GetMinItemsString();
+            case kValidateErrorUniqueItems:             return GetUniqueItemsString();
+            case kValidateErrorAdditionalItems:         return GetAdditionalItemsString();
+
+            case kValidateErrorMaxProperties:           return GetMaxPropertiesString();
+            case kValidateErrorMinProperties:           return GetMinPropertiesString();
+            case kValidateErrorRequired:                return GetRequiredString();
+            case kValidateErrorAdditionalProperties:    return GetAdditionalPropertiesString();
+            case kValidateErrorPatternProperties:       return GetPatternPropertiesString();
+            case kValidateErrorDependencies:            return GetDependenciesString();
+
+            case kValidateErrorEnum:                    return GetEnumString();
+            case kValidateErrorType:                    return GetTypeString();
+
+            case kValidateErrorOneOf:                   return GetOneOfString();
+            case kValidateErrorOneOfMatch:              return GetOneOfString(); // Same
+            case kValidateErrorAllOf:                   return GetAllOfString();
+            case kValidateErrorAnyOf:                   return GetAnyOfString();
+            case kValidateErrorNot:                     return GetNotString();
+
+            default:                                    return GetNullString();
+        }
+    }
+
+
     // Generate functions for string literal according to Ch
 #define RAPIDJSON_STRING_(name, ...) \
     static const ValueType& Get##name##String() {\
@@ -1190,31 +1268,32 @@
             context.validators = static_cast<ISchemaValidator**>(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_));
             context.validatorCount = validatorCount_;
 
+            // Always return after first failure for these sub-validators
             if (allOf_.schemas)
-                CreateSchemaValidators(context, allOf_);
+                CreateSchemaValidators(context, allOf_, false);
 
             if (anyOf_.schemas)
-                CreateSchemaValidators(context, anyOf_);
+                CreateSchemaValidators(context, anyOf_, false);
             
             if (oneOf_.schemas)
-                CreateSchemaValidators(context, oneOf_);
+                CreateSchemaValidators(context, oneOf_, false);
             
             if (not_)
-                context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_);
-            
+                context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_, false);
+
             if (hasSchemaDependencies_) {
                 for (SizeType i = 0; i < propertyCount_; i++)
                     if (properties_[i].dependenciesSchema)
-                        context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema);
+                        context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema, false);
             }
         }
 
         return true;
     }
 
-    void CreateSchemaValidators(Context& context, const SchemaArray& schemas) const {
+    void CreateSchemaValidators(Context& context, const SchemaArray& schemas, const bool inheritContinueOnErrors) const {
         for (SizeType i = 0; i < schemas.count; i++)
-            context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i]);
+            context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i], inheritContinueOnErrors);
     }
 
     // O(n)
@@ -1234,19 +1313,19 @@
     bool CheckInt(Context& context, int64_t i) const {
         if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
             DisallowedType(context, GetIntegerString());
-            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+            RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
         }
 
         if (!minimum_.IsNull()) {
             if (minimum_.IsInt64()) {
                 if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) {
                     context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
-                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
+                    RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum);
                 }
             }
             else if (minimum_.IsUint64()) {
                 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
-                RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64()
+                RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum); // i <= max(int64_t) < minimum.GetUint64()
             }
             else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
                 return false;
@@ -1256,7 +1335,7 @@
             if (maximum_.IsInt64()) {
                 if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) {
                     context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
-                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
+                    RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum);
                 }
             }
             else if (maximum_.IsUint64()) { }
@@ -1269,7 +1348,7 @@
             if (multipleOf_.IsUint64()) {
                 if (static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) {
                     context.error_handler.NotMultipleOf(i, multipleOf_);
-                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
+                    RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf);
                 }
             }
             else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
@@ -1282,14 +1361,14 @@
     bool CheckUint(Context& context, uint64_t i) const {
         if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
             DisallowedType(context, GetIntegerString());
-            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+            RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
         }
 
         if (!minimum_.IsNull()) {
             if (minimum_.IsUint64()) {
                 if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) {
                     context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
-                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
+                    RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum);
                 }
             }
             else if (minimum_.IsInt64())
@@ -1302,12 +1381,12 @@
             if (maximum_.IsUint64()) {
                 if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) {
                     context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
-                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
+                    RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum);
                 }
             }
             else if (maximum_.IsInt64()) {
                 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
-                RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); // i >= 0 > maximum_
+                RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum); // i >= 0 > maximum_
             }
             else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
                 return false;
@@ -1317,7 +1396,7 @@
             if (multipleOf_.IsUint64()) {
                 if (i % multipleOf_.GetUint64() != 0) {
                     context.error_handler.NotMultipleOf(i, multipleOf_);
-                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
+                    RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf);
                 }
             }
             else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
@@ -1330,7 +1409,7 @@
     bool CheckDoubleMinimum(Context& context, double d) const {
         if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) {
             context.error_handler.BelowMinimum(d, minimum_, exclusiveMinimum_);
-            RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
+            RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum);
         }
         return true;
     }
@@ -1338,7 +1417,7 @@
     bool CheckDoubleMaximum(Context& context, double d) const {
         if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) {
             context.error_handler.AboveMaximum(d, maximum_, exclusiveMaximum_);
-            RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
+            RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum);
         }
         return true;
     }
@@ -1349,7 +1428,7 @@
         double r = a - q * b;
         if (r > 0.0) {
             context.error_handler.NotMultipleOf(d, multipleOf_);
-            RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
+            RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf);
         }
         return true;
     }
@@ -1763,8 +1842,7 @@
 class GenericSchemaValidator :
     public internal::ISchemaStateFactory<typename SchemaDocumentType::SchemaType>, 
     public internal::ISchemaValidator,
-    public internal::IValidationErrorHandler<typename SchemaDocumentType::SchemaType>
-{
+    public internal::IValidationErrorHandler<typename SchemaDocumentType::SchemaType> {
 public:
     typedef typename SchemaDocumentType::SchemaType SchemaType;
     typedef typename SchemaDocumentType::PointerType PointerType;
@@ -1797,7 +1875,8 @@
         error_(kObjectType),
         currentError_(),
         missingDependents_(),
-        valid_(true)
+        valid_(true),
+        flags_(kValidateDefaultFlags)
 #if RAPIDJSON_SCHEMA_VERBOSE
         , depth_(0)
 #endif
@@ -1828,7 +1907,8 @@
         error_(kObjectType),
         currentError_(),
         missingDependents_(),
-        valid_(true)
+        valid_(true),
+        flags_(kValidateDefaultFlags)
 #if RAPIDJSON_SCHEMA_VERBOSE
         , depth_(0)
 #endif
@@ -1846,31 +1926,61 @@
         while (!schemaStack_.Empty())
             PopSchema();
         documentStack_.Clear();
+        ResetError();
+    }
+
+    //! Reset the error state.
+    void ResetError() {
         error_.SetObject();
         currentError_.SetNull();
         missingDependents_.SetNull();
         valid_ = true;
     }
 
+    //! Implementation of ISchemaValidator
+    void SetValidateFlags(unsigned flags) {
+        flags_ = flags;
+    }
+    virtual unsigned GetValidateFlags() const {
+        return flags_;
+    }
+
     //! Checks whether the current state is valid.
     // Implementation of ISchemaValidator
-    virtual bool IsValid() const { return valid_; }
+    virtual bool IsValid() const {
+        if (!valid_) return false;
+        if (GetContinueOnErrors() && !error_.ObjectEmpty()) return false;
+        return true;
+    }
 
     //! Gets the error object.
     ValueType& GetError() { return error_; }
     const ValueType& GetError() const { return error_; }
 
     //! Gets the JSON pointer pointed to the invalid schema.
+    //  If reporting all errors, the stack will be empty.
     PointerType GetInvalidSchemaPointer() const {
         return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer();
     }
 
     //! Gets the keyword of invalid schema.
+    //  If reporting all errors, the stack will be empty, so return "errors".
     const Ch* GetInvalidSchemaKeyword() const {
-        return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword;
+        if (!schemaStack_.Empty()) return CurrentContext().invalidKeyword;
+        if (GetContinueOnErrors() && !error_.ObjectEmpty()) return (const Ch*)GetErrorsString();
+        return 0;
+    }
+
+    //! Gets the error code of invalid schema.
+    //  If reporting all errors, the stack will be empty, so return kValidateErrors.
+    ValidateErrorCode GetInvalidSchemaCode() const {
+        if (!schemaStack_.Empty()) return CurrentContext().invalidCode;
+        if (GetContinueOnErrors() && !error_.ObjectEmpty()) return kValidateErrors;
+        return kValidateErrorNone;
     }
 
     //! Gets the JSON pointer pointed to the invalid value.
+    //  If reporting all errors, the stack will be empty.
     PointerType GetInvalidDocumentPointer() const {
         if (documentStack_.Empty()) {
             return PointerType();
@@ -1881,64 +1991,64 @@
     }
 
     void NotMultipleOf(int64_t actual, const SValue& expected) {
-        AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected);
+        AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
     }
     void NotMultipleOf(uint64_t actual, const SValue& expected) {
-        AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected);
+        AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
     }
     void NotMultipleOf(double actual, const SValue& expected) {
-        AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected);
+        AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
     }
     void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) {
-        AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected,
+        AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected,
             exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
     }
     void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) {
-        AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected,
+        AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected,
             exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
     }
     void AboveMaximum(double actual, const SValue& expected, bool exclusive) {
-        AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected,
+        AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected,
             exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
     }
     void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) {
-        AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected,
+        AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected,
             exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
     }
     void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) {
-        AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected,
+        AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected,
             exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
     }
     void BelowMinimum(double actual, const SValue& expected, bool exclusive) {
-        AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected,
+        AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected,
             exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
     }
 
     void TooLong(const Ch* str, SizeType length, SizeType expected) {
-        AddNumberError(SchemaType::GetMaxLengthString(),
+        AddNumberError(kValidateErrorMaxLength,
             ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
     }
     void TooShort(const Ch* str, SizeType length, SizeType expected) {
-        AddNumberError(SchemaType::GetMinLengthString(),
+        AddNumberError(kValidateErrorMinLength,
             ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
     }
     void DoesNotMatch(const Ch* str, SizeType length) {
         currentError_.SetObject();
         currentError_.AddMember(GetActualString(), ValueType(str, length, GetStateAllocator()).Move(), GetStateAllocator());
-        AddCurrentError(SchemaType::GetPatternString());
+        AddCurrentError(kValidateErrorPattern);
     }
 
     void DisallowedItem(SizeType index) {
         currentError_.SetObject();
         currentError_.AddMember(GetDisallowedString(), ValueType(index).Move(), GetStateAllocator());
-        AddCurrentError(SchemaType::GetAdditionalItemsString(), true);
+        AddCurrentError(kValidateErrorAdditionalItems, true);
     }
     void TooFewItems(SizeType actualCount, SizeType expectedCount) {
-        AddNumberError(SchemaType::GetMinItemsString(),
+        AddNumberError(kValidateErrorMinItems,
             ValueType(actualCount).Move(), SValue(expectedCount).Move());
     }
     void TooManyItems(SizeType actualCount, SizeType expectedCount) {
-        AddNumberError(SchemaType::GetMaxItemsString(),
+        AddNumberError(kValidateErrorMaxItems,
             ValueType(actualCount).Move(), SValue(expectedCount).Move());
     }
     void DuplicateItems(SizeType index1, SizeType index2) {
@@ -1947,15 +2057,15 @@
         duplicates.PushBack(index2, GetStateAllocator());
         currentError_.SetObject();
         currentError_.AddMember(GetDuplicatesString(), duplicates, GetStateAllocator());
-        AddCurrentError(SchemaType::GetUniqueItemsString(), true);
+        AddCurrentError(kValidateErrorUniqueItems, true);
     }
 
     void TooManyProperties(SizeType actualCount, SizeType expectedCount) {
-        AddNumberError(SchemaType::GetMaxPropertiesString(),
+        AddNumberError(kValidateErrorMaxProperties,
             ValueType(actualCount).Move(), SValue(expectedCount).Move());
     }
     void TooFewProperties(SizeType actualCount, SizeType expectedCount) {
-        AddNumberError(SchemaType::GetMinPropertiesString(),
+        AddNumberError(kValidateErrorMinProperties,
             ValueType(actualCount).Move(), SValue(expectedCount).Move());
     }
     void StartMissingProperties() {
@@ -1970,7 +2080,7 @@
         ValueType error(kObjectType);
         error.AddMember(GetMissingString(), currentError_, GetStateAllocator());
         currentError_ = error;
-        AddCurrentError(SchemaType::GetRequiredString());
+        AddCurrentError(kValidateErrorRequired);
         return true;
     }
     void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) {
@@ -1980,7 +2090,7 @@
     void DisallowedProperty(const Ch* name, SizeType length) {
         currentError_.SetObject();
         currentError_.AddMember(GetDisallowedString(), ValueType(name, length, GetStateAllocator()).Move(), GetStateAllocator());
-        AddCurrentError(SchemaType::GetAdditionalPropertiesString(), true);
+        AddCurrentError(kValidateErrorAdditionalProperties, true);
     }
 
     void StartDependencyErrors() {
@@ -1993,9 +2103,20 @@
         missingDependents_.PushBack(ValueType(targetName, GetStateAllocator()).Move(), GetStateAllocator());
     }
     void EndMissingDependentProperties(const SValue& sourceName) {
-        if (!missingDependents_.Empty())
-            currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(),
-                missingDependents_, GetStateAllocator());
+        if (!missingDependents_.Empty()) {
+            // Create equivalent 'required' error
+            ValueType error(kObjectType);
+            ValidateErrorCode code = kValidateErrorRequired;
+            error.AddMember(GetMissingString(), missingDependents_.Move(), GetStateAllocator());
+            AddErrorCode(error, code);
+            AddErrorInstanceLocation(error, false);
+            // When appending to a pointer ensure its allocator is used
+            PointerType schemaRef = GetInvalidSchemaPointer().Append(SchemaType::GetValidateErrorKeyword(kValidateErrorDependencies), &GetInvalidSchemaPointer().GetAllocator());
+            AddErrorSchemaLocation(error, schemaRef.Append(sourceName.GetString(), sourceName.GetStringLength(), &GetInvalidSchemaPointer().GetAllocator()));
+            ValueType wrapper(kObjectType);
+            wrapper.AddMember(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator()).Move(), error, GetStateAllocator());
+            currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(), wrapper, GetStateAllocator());
+        }
     }
     void AddDependencySchemaError(const SValue& sourceName, ISchemaValidator* subvalidator) {
         currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(),
@@ -2007,13 +2128,13 @@
         ValueType error(kObjectType);
         error.AddMember(GetErrorsString(), currentError_, GetStateAllocator());
         currentError_ = error;
-        AddCurrentError(SchemaType::GetDependenciesString());
+        AddCurrentError(kValidateErrorDependencies);
         return true;
     }
 
-    void DisallowedValue() {
+    void DisallowedValue(const ValidateErrorCode code = kValidateErrorEnum) {
         currentError_.SetObject();
-        AddCurrentError(SchemaType::GetEnumString());
+        AddCurrentError(code);
     }
     void StartDisallowedType() {
         currentError_.SetArray();
@@ -2026,22 +2147,24 @@
         error.AddMember(GetExpectedString(), currentError_, GetStateAllocator());
         error.AddMember(GetActualString(), ValueType(actualType, GetStateAllocator()).Move(), GetStateAllocator());
         currentError_ = error;
-        AddCurrentError(SchemaType::GetTypeString());
+        AddCurrentError(kValidateErrorType);
     }
     void NotAllOf(ISchemaValidator** subvalidators, SizeType count) {
-        for (SizeType i = 0; i < count; ++i) {
-            MergeError(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError());
-        }
+        // Treat allOf like oneOf and anyOf to match https://rapidjson.org/md_doc_schema.html#allOf-anyOf-oneOf
+        AddErrorArray(kValidateErrorAllOf, subvalidators, count);
+        //for (SizeType i = 0; i < count; ++i) {
+        //    MergeError(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError());
+        //}
     }
     void NoneOf(ISchemaValidator** subvalidators, SizeType count) {
-        AddErrorArray(SchemaType::GetAnyOfString(), subvalidators, count);
+        AddErrorArray(kValidateErrorAnyOf, subvalidators, count);
     }
-    void NotOneOf(ISchemaValidator** subvalidators, SizeType count) {
-        AddErrorArray(SchemaType::GetOneOfString(), subvalidators, count);
+    void NotOneOf(ISchemaValidator** subvalidators, SizeType count, bool matched = false) {
+        AddErrorArray(matched ? kValidateErrorOneOfMatch : kValidateErrorOneOf, subvalidators, count);
     }
     void Disallowed() {
         currentError_.SetObject();
-        AddCurrentError(SchemaType::GetNotString());
+        AddCurrentError(kValidateErrorNot);
     }
 
 #define RAPIDJSON_STRING_(name, ...) \
@@ -2058,6 +2181,8 @@
     RAPIDJSON_STRING_(Disallowed, 'd', 'i', 's', 'a', 'l', 'l', 'o', 'w', 'e', 'd')
     RAPIDJSON_STRING_(Missing, 'm', 'i', 's', 's', 'i', 'n', 'g')
     RAPIDJSON_STRING_(Errors, 'e', 'r', 'r', 'o', 'r', 's')
+    RAPIDJSON_STRING_(ErrorCode, 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e')
+    RAPIDJSON_STRING_(ErrorMessage, 'e', 'r', 'r', 'o', 'r', 'M', 'e', 's', 's', 'a', 'g', 'e')
     RAPIDJSON_STRING_(Duplicates, 'd', 'u', 'p', 'l', 'i', 'c', 'a', 't', 'e', 's')
 
 #undef RAPIDJSON_STRING_
@@ -2075,7 +2200,7 @@
 
 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\
     if (!valid_) return false; \
-    if (!BeginValue() || !CurrentSchema().method arg1) {\
+    if ((!BeginValue() && !GetContinueOnErrors()) || (!CurrentSchema().method arg1 && !GetContinueOnErrors())) {\
         RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\
         return valid_ = false;\
     }
@@ -2093,7 +2218,8 @@
     }
 
 #define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\
-    return valid_ = EndValue() && (!outputHandler_ || outputHandler_->method arg2)
+    valid_ = (EndValue() || GetContinueOnErrors()) && (!outputHandler_ || outputHandler_->method arg2);\
+    return valid_;
 
 #define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \
     RAPIDJSON_SCHEMA_HANDLE_BEGIN_   (method, arg1);\
@@ -2121,15 +2247,15 @@
     bool Key(const Ch* str, SizeType len, bool copy) {
         if (!valid_) return false;
         AppendToken(str, len);
-        if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false;
+        if (!CurrentSchema().Key(CurrentContext(), str, len, copy) && !GetContinueOnErrors()) return valid_ = false;
         RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy));
         return valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy);
     }
     
-    bool EndObject(SizeType memberCount) { 
+    bool EndObject(SizeType memberCount) {
         if (!valid_) return false;
         RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount));
-        if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false;
+        if (!CurrentSchema().EndObject(CurrentContext(), memberCount) && !GetContinueOnErrors()) return valid_ = false;
         RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount));
     }
 
@@ -2142,7 +2268,7 @@
     bool EndArray(SizeType elementCount) {
         if (!valid_) return false;
         RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount));
-        if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false;
+        if (!CurrentSchema().EndArray(CurrentContext(), elementCount) && !GetContinueOnErrors()) return valid_ = false;
         RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));
     }
 
@@ -2152,12 +2278,14 @@
 #undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
 
     // Implementation of ISchemaStateFactory<SchemaType>
-    virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root) {
-        return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, documentStack_.template Bottom<char>(), documentStack_.GetSize(),
+    virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root, const bool inheritContinueOnErrors) {
+        ISchemaValidator* sv = new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, documentStack_.template Bottom<char>(), documentStack_.GetSize(),
 #if RAPIDJSON_SCHEMA_VERBOSE
         depth_ + 1,
 #endif
         &GetStateAllocator());
+        sv->SetValidateFlags(inheritContinueOnErrors ? GetValidateFlags() : GetValidateFlags() & ~(unsigned)kValidateContinueOnErrorFlag);
+        return sv;
     }
 
     virtual void DestroySchemaValidator(ISchemaValidator* validator) {
@@ -2214,7 +2342,8 @@
         error_(kObjectType),
         currentError_(),
         missingDependents_(),
-        valid_(true)
+        valid_(true),
+        flags_(kValidateDefaultFlags)
 #if RAPIDJSON_SCHEMA_VERBOSE
         , depth_(depth)
 #endif
@@ -2229,6 +2358,10 @@
         return *stateAllocator_;
     }
 
+    bool GetContinueOnErrors() const {
+        return flags_ & kValidateContinueOnErrorFlag;
+    }
+
     bool BeginValue() {
         if (schemaStack_.Empty())
             PushSchema(root_);
@@ -2236,7 +2369,7 @@
             if (CurrentContext().inArray)
                 internal::TokenHelper<internal::Stack<StateAllocator>, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex);
 
-            if (!CurrentSchema().BeginValue(CurrentContext()))
+            if (!CurrentSchema().BeginValue(CurrentContext()) && !GetContinueOnErrors())
                 return false;
 
             SizeType count = CurrentContext().patternPropertiesSchemaCount;
@@ -2252,7 +2385,7 @@
                 SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount;
                 va = static_cast<ISchemaValidator**>(MallocState(sizeof(ISchemaValidator*) * count));
                 for (SizeType i = 0; i < count; i++)
-                    va[validatorCount++] = CreateSchemaValidator(*sa[i]);
+                    va[validatorCount++] = CreateSchemaValidator(*sa[i], true);  // Inherit continueOnError
             }
 
             CurrentContext().arrayUniqueness = valueUniqueness;
@@ -2261,7 +2394,7 @@
     }
 
     bool EndValue() {
-        if (!CurrentSchema().EndValue(CurrentContext()))
+        if (!CurrentSchema().EndValue(CurrentContext()) && !GetContinueOnErrors())
             return false;
 
 #if RAPIDJSON_SCHEMA_VERBOSE
@@ -2272,21 +2405,27 @@
         documentStack_.template Pop<Ch>(1);
         internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom<Ch>());
 #endif
-
-        uint64_t h = CurrentContext().arrayUniqueness ? static_cast<HasherType*>(CurrentContext().hasher)->GetHashCode() : 0;
+        void* hasher = CurrentContext().hasher;
+        uint64_t h = hasher && CurrentContext().arrayUniqueness ? static_cast<HasherType*>(hasher)->GetHashCode() : 0;
         
         PopSchema();
 
         if (!schemaStack_.Empty()) {
             Context& context = CurrentContext();
-            if (context.valueUniqueness) {
+            // Only check uniqueness if there is a hasher
+            if (hasher && context.valueUniqueness) {
                 HashCodeArray* a = static_cast<HashCodeArray*>(context.arrayElementHashCodes);
                 if (!a)
                     CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType);
                 for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr)
                     if (itr->GetUint64() == h) {
                         DuplicateItems(static_cast<SizeType>(itr - a->Begin()), a->Size());
-                        RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString());
+                        // Cleanup before returning if continuing
+                        if (GetContinueOnErrors()) {
+                            a->PushBack(h, GetStateAllocator());
+                            while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) != '/');
+                        }
+                        RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorUniqueItems);
                     }
                 a->PushBack(h, GetStateAllocator());
             }
@@ -2327,25 +2466,32 @@
         c->~Context();
     }
 
-    void AddErrorLocation(ValueType& result, bool parent) {
+    void AddErrorInstanceLocation(ValueType& result, bool parent) {
         GenericStringBuffer<EncodingType> sb;
         PointerType instancePointer = GetInvalidDocumentPointer();
         ((parent && instancePointer.GetTokenCount() > 0)
-            ? PointerType(instancePointer.GetTokens(), instancePointer.GetTokenCount() - 1)
-            : instancePointer).StringifyUriFragment(sb);
+         ? PointerType(instancePointer.GetTokens(), instancePointer.GetTokenCount() - 1)
+         : instancePointer).StringifyUriFragment(sb);
         ValueType instanceRef(sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)),
-            GetStateAllocator());
+                              GetStateAllocator());
         result.AddMember(GetInstanceRefString(), instanceRef, GetStateAllocator());
-        sb.Clear();
-        memcpy(sb.Push(CurrentSchema().GetURI().GetStringLength()),
-            CurrentSchema().GetURI().GetString(),
-            CurrentSchema().GetURI().GetStringLength() * sizeof(Ch));
-        GetInvalidSchemaPointer().StringifyUriFragment(sb);
+    }
+
+    void AddErrorSchemaLocation(ValueType& result, PointerType schema = PointerType()) {
+        GenericStringBuffer<EncodingType> sb;
+        SizeType len = CurrentSchema().GetURI().GetStringLength();
+        if (len) memcpy(sb.Push(len), CurrentSchema().GetURI().GetString(), len * sizeof(Ch));
+        if (schema.GetTokenCount()) schema.StringifyUriFragment(sb);
+        else GetInvalidSchemaPointer().StringifyUriFragment(sb);
         ValueType schemaRef(sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)),
             GetStateAllocator());
         result.AddMember(GetSchemaRefString(), schemaRef, GetStateAllocator());
     }
 
+    void AddErrorCode(ValueType& result, const ValidateErrorCode code) {
+        result.AddMember(GetErrorCodeString(), code, GetStateAllocator());
+    }
+
     void AddError(ValueType& keyword, ValueType& error) {
         typename ValueType::MemberIterator member = error_.FindMember(keyword);
         if (member == error_.MemberEnd())
@@ -2360,9 +2506,11 @@
         }
     }
 
-    void AddCurrentError(const typename SchemaType::ValueType& keyword, bool parent = false) {
-        AddErrorLocation(currentError_, parent);
-        AddError(ValueType(keyword, GetStateAllocator(), false).Move(), currentError_);
+    void AddCurrentError(const ValidateErrorCode code, bool parent = false) {
+        AddErrorCode(currentError_, code);
+        AddErrorInstanceLocation(currentError_, parent);
+        AddErrorSchemaLocation(currentError_);
+        AddError(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator(), false).Move(), currentError_);
     }
 
     void MergeError(ValueType& other) {
@@ -2371,24 +2519,24 @@
         }
     }
 
-    void AddNumberError(const typename SchemaType::ValueType& keyword, ValueType& actual, const SValue& expected,
+    void AddNumberError(const ValidateErrorCode code, ValueType& actual, const SValue& expected,
         const typename SchemaType::ValueType& (*exclusive)() = 0) {
         currentError_.SetObject();
         currentError_.AddMember(GetActualString(), actual, GetStateAllocator());
         currentError_.AddMember(GetExpectedString(), ValueType(expected, GetStateAllocator()).Move(), GetStateAllocator());
         if (exclusive)
             currentError_.AddMember(ValueType(exclusive(), GetStateAllocator()).Move(), true, GetStateAllocator());
-        AddCurrentError(keyword);
+        AddCurrentError(code);
     }
 
-    void AddErrorArray(const typename SchemaType::ValueType& keyword,
+    void AddErrorArray(const ValidateErrorCode code,
         ISchemaValidator** subvalidators, SizeType count) {
         ValueType errors(kArrayType);
         for (SizeType i = 0; i < count; ++i)
             errors.PushBack(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError(), GetStateAllocator());
         currentError_.SetObject();
         currentError_.AddMember(GetErrorsString(), errors, GetStateAllocator());
-        AddCurrentError(keyword);
+        AddCurrentError(code);
     }
 
     const SchemaType& CurrentSchema() const { return *schemaStack_.template Top<Context>()->schema; }
@@ -2408,6 +2556,7 @@
     ValueType currentError_;
     ValueType missingDependents_;
     bool valid_;
+    unsigned flags_;
 #if RAPIDJSON_SCHEMA_VERBOSE
     unsigned depth_;
 #endif
@@ -2445,7 +2594,7 @@
         \param is Input stream.
         \param sd Schema document.
     */
-    SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), error_(kObjectType), isValid_(true) {}
+    SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), invalidSchemaCode_(kValidateErrorNone), error_(kObjectType), isValid_(true) {}
 
     template <typename Handler>
     bool operator()(Handler& handler) {
@@ -2463,6 +2612,7 @@
         else {
             invalidSchemaPointer_ = validator.GetInvalidSchemaPointer();
             invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword();
+            invalidSchemaCode_ = validator.GetInvalidSchemaCode();
             invalidDocumentPointer_ = validator.GetInvalidDocumentPointer();
             error_.CopyFrom(validator.GetError(), allocator_);
         }
@@ -2476,6 +2626,7 @@
     const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; }
     const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; }
     const ValueType& GetError() const { return error_; }
+    ValidateErrorCode GetInvalidSchemaCode() const { return invalidSchemaCode_; }
 
 private:
     InputStream& is_;
@@ -2485,6 +2636,7 @@
     PointerType invalidSchemaPointer_;
     const Ch* invalidSchemaKeyword_;
     PointerType invalidDocumentPointer_;
+    ValidateErrorCode invalidSchemaCode_;
     StackAllocator allocator_;
     ValueType error_;
     bool isValid_;
diff --git a/include/rapidjson/stream.h b/include/rapidjson/stream.h
index 7f2643e..1fd7091 100644
--- a/include/rapidjson/stream.h
+++ b/include/rapidjson/stream.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 //
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/stringbuffer.h b/include/rapidjson/stringbuffer.h
index 4e38b82..82ad3ca 100644
--- a/include/rapidjson/stringbuffer.h
+++ b/include/rapidjson/stringbuffer.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/include/rapidjson/writer.h b/include/rapidjson/writer.h
index 51dd86d..8b38921 100644
--- a/include/rapidjson/writer.h
+++ b/include/rapidjson/writer.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/readme.md b/readme.md
index fdb3422..ac683b0 100644
--- a/readme.md
+++ b/readme.md
@@ -6,7 +6,7 @@
 
 Tencent is pleased to support the open source community by making RapidJSON available.
 
-Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 
 * [RapidJSON GitHub](https://github.com/Tencent/rapidjson/)
 * RapidJSON Documentation
@@ -196,7 +196,7 @@
 ```
 Tencent is pleased to support the open source community by making RapidJSON available.
 
-Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 
 Licensed under the MIT License (the "License"); you may not use this file except
 in compliance with the License. You may obtain a copy of the License at
@@ -207,4 +207,4 @@
 under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
 CONDITIONS OF ANY KIND, either express or implied. See the License for the 
 specific language governing permissions and limitations under the License.
-```
\ No newline at end of file
+```
diff --git a/readme.zh-cn.md b/readme.zh-cn.md
index ccf1669..216802e 100644
--- a/readme.zh-cn.md
+++ b/readme.zh-cn.md
@@ -6,7 +6,7 @@
 
 Tencent is pleased to support the open source community by making RapidJSON available.
 
-Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 
 * [RapidJSON GitHub](https://github.com/Tencent/rapidjson/)
 * RapidJSON 文档
@@ -149,4 +149,4 @@
   * [prettyauto](https://github.com/Tencent/rapidjson/blob/master/example/prettyauto/prettyauto.cpp): [pretty](https://github.com/Tencent/rapidjson/blob/master/example/pretty/pretty.cpp) 的修改版本,可自动处理任何 UTF 编码的 JSON。
   * [parsebyparts](https://github.com/Tencent/rapidjson/blob/master/example/parsebyparts/parsebyparts.cpp): 这例子中的 `AsyncDocumentParser` 类使用 C++ 线程来逐段解析 JSON。
   * [filterkey](https://github.com/Tencent/rapidjson/blob/master/example/filterkey/filterkey.cpp): 移取使用者指定的键值的命令行工具。
-  * [filterkeydom](https://github.com/Tencent/rapidjson/blob/master/example/filterkey/filterkey.cpp): 如上的工具,但展示如何使用生成器(generator)去填充一个 `Document`。
\ No newline at end of file
+  * [filterkeydom](https://github.com/Tencent/rapidjson/blob/master/example/filterkey/filterkey.cpp): 如上的工具,但展示如何使用生成器(generator)去填充一个 `Document`。
diff --git a/test/perftest/misctest.cpp b/test/perftest/misctest.cpp
index d81062f..f43b050 100644
--- a/test/perftest/misctest.cpp
+++ b/test/perftest/misctest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/perftest/perftest.cpp b/test/perftest/perftest.cpp
index 4e79f1f..b149a4c 100644
--- a/test/perftest/perftest.cpp
+++ b/test/perftest/perftest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/perftest/perftest.h b/test/perftest/perftest.h
index 953f95d..a83a6ed 100644
--- a/test/perftest/perftest.h
+++ b/test/perftest/perftest.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/perftest/platformtest.cpp b/test/perftest/platformtest.cpp
index 9b9c246..c490da7 100644
--- a/test/perftest/platformtest.cpp
+++ b/test/perftest/platformtest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/perftest/rapidjsontest.cpp b/test/perftest/rapidjsontest.cpp
index 9492cc5..24e7120 100644
--- a/test/perftest/rapidjsontest.cpp
+++ b/test/perftest/rapidjsontest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/unittest/allocatorstest.cpp b/test/unittest/allocatorstest.cpp
index 2202c11..c541f04 100644
--- a/test/unittest/allocatorstest.cpp
+++ b/test/unittest/allocatorstest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/unittest/bigintegertest.cpp b/test/unittest/bigintegertest.cpp
index 6e9d4c6..fad5438 100644
--- a/test/unittest/bigintegertest.cpp
+++ b/test/unittest/bigintegertest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/unittest/clzlltest.cpp b/test/unittest/clzlltest.cpp
index a5b3e2e..ad465e1 100644
--- a/test/unittest/clzlltest.cpp
+++ b/test/unittest/clzlltest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/unittest/cursorstreamwrappertest.cpp b/test/unittest/cursorstreamwrappertest.cpp
index 2ce2810..dad3359 100644
--- a/test/unittest/cursorstreamwrappertest.cpp
+++ b/test/unittest/cursorstreamwrappertest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 //
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/unittest/documenttest.cpp b/test/unittest/documenttest.cpp
index 5429802..472165f 100644
--- a/test/unittest/documenttest.cpp
+++ b/test/unittest/documenttest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/unittest/dtoatest.cpp b/test/unittest/dtoatest.cpp
index afd76eb..66576bd 100644
--- a/test/unittest/dtoatest.cpp
+++ b/test/unittest/dtoatest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/unittest/encodedstreamtest.cpp b/test/unittest/encodedstreamtest.cpp
index bc234d3..d9b87e9 100644
--- a/test/unittest/encodedstreamtest.cpp
+++ b/test/unittest/encodedstreamtest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/unittest/encodingstest.cpp b/test/unittest/encodingstest.cpp
index 82cf777..455881e 100644
--- a/test/unittest/encodingstest.cpp
+++ b/test/unittest/encodingstest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/unittest/filestreamtest.cpp b/test/unittest/filestreamtest.cpp
index 0e243ab..de0b4d1 100644
--- a/test/unittest/filestreamtest.cpp
+++ b/test/unittest/filestreamtest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/unittest/fwdtest.cpp b/test/unittest/fwdtest.cpp
index 1936d97..e9c7078 100644
--- a/test/unittest/fwdtest.cpp
+++ b/test/unittest/fwdtest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/unittest/istreamwrappertest.cpp b/test/unittest/istreamwrappertest.cpp
index 0c3e5c4..f0cdb2d 100644
--- a/test/unittest/istreamwrappertest.cpp
+++ b/test/unittest/istreamwrappertest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/unittest/itoatest.cpp b/test/unittest/itoatest.cpp
index f7524b8..4c834de 100644
--- a/test/unittest/itoatest.cpp
+++ b/test/unittest/itoatest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 //
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/unittest/jsoncheckertest.cpp b/test/unittest/jsoncheckertest.cpp
index 47c2b56..19e1f1c 100644
--- a/test/unittest/jsoncheckertest.cpp
+++ b/test/unittest/jsoncheckertest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/unittest/namespacetest.cpp b/test/unittest/namespacetest.cpp
index 1814724..e33e6d5 100644
--- a/test/unittest/namespacetest.cpp
+++ b/test/unittest/namespacetest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/unittest/ostreamwrappertest.cpp b/test/unittest/ostreamwrappertest.cpp
index 50f8da6..c9bc5f4 100644
--- a/test/unittest/ostreamwrappertest.cpp
+++ b/test/unittest/ostreamwrappertest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/unittest/pointertest.cpp b/test/unittest/pointertest.cpp
index 4629f76..4371803 100644
--- a/test/unittest/pointertest.cpp
+++ b/test/unittest/pointertest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
@@ -1529,6 +1529,38 @@
     }
 }
 
+TEST(Pointer, ResolveOnObject) {
+    Document d;
+    EXPECT_FALSE(d.Parse("{\"a\": 123}").HasParseError());
+
+    {
+        Value::ConstObject o = static_cast<const Document&>(d).GetObject();
+        EXPECT_EQ(123, Pointer("/a").Get(o)->GetInt());
+    }
+
+    {
+        Value::Object o = d.GetObject();
+        Pointer("/a").Set(o, 456, d.GetAllocator());
+        EXPECT_EQ(456, Pointer("/a").Get(o)->GetInt());
+    }
+}
+
+TEST(Pointer, ResolveOnArray) {
+    Document d;
+    EXPECT_FALSE(d.Parse("[1, 2, 3]").HasParseError());
+
+    {
+        Value::ConstArray a = static_cast<const Document&>(d).GetArray();
+        EXPECT_EQ(2, Pointer("/1").Get(a)->GetInt());
+    }
+
+    {
+        Value::Array a = d.GetArray();
+        Pointer("/1").Set(a, 123, d.GetAllocator());
+        EXPECT_EQ(123, Pointer("/1").Get(a)->GetInt());
+    }
+}
+
 TEST(Pointer, LessThan) {
     static const struct {
         const char *str;
diff --git a/test/unittest/prettywritertest.cpp b/test/unittest/prettywritertest.cpp
index 4bf02bd..0b7feef 100644
--- a/test/unittest/prettywritertest.cpp
+++ b/test/unittest/prettywritertest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp
index 2a4a626..d3fcdef 100644
--- a/test/unittest/readertest.cpp
+++ b/test/unittest/readertest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 //
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/unittest/regextest.cpp b/test/unittest/regextest.cpp
index cf89973..a288622 100644
--- a/test/unittest/regextest.cpp
+++ b/test/unittest/regextest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/unittest/schematest.cpp b/test/unittest/schematest.cpp
index 3261069..f381b4e 100644
--- a/test/unittest/schematest.cpp
+++ b/test/unittest/schematest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
@@ -12,10 +12,14 @@
 // CONDITIONS OF ANY KIND, either express or implied. See the License for the 
 // specific language governing permissions and limitations under the License.
 
+#define RAPIDJSON_SCHEMA_VERBOSE 0
+
 #include "unittest.h"
 #include "rapidjson/schema.h"
 #include "rapidjson/stringbuffer.h"
 #include "rapidjson/writer.h"
+#include "rapidjson/error/error.h"
+#include "rapidjson/error/en.h"
 
 #ifdef __clang__
 RAPIDJSON_DIAG_PUSH
@@ -114,11 +118,18 @@
     EXPECT_FALSE(d.HasParseError());\
     EXPECT_TRUE(expected == d.Accept(validator));\
     EXPECT_TRUE(expected == validator.IsValid());\
+    ValidateErrorCode code = validator.GetInvalidSchemaCode();\
+    if (expected) {\
+      EXPECT_TRUE(code == kValidateErrorNone);\
+      EXPECT_TRUE(validator.GetInvalidSchemaKeyword() == 0);\
+    }\
     if ((expected) && !validator.IsValid()) {\
         StringBuffer sb;\
         validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);\
         printf("Invalid schema: %s\n", sb.GetString());\
         printf("Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());\
+        printf("Invalid code: %d\n", code);\
+        printf("Invalid message: %s\n", GetValidateError_En(code));\
         sb.Clear();\
         validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);\
         printf("Invalid document: %s\n", sb.GetString());\
@@ -131,19 +142,23 @@
 
 #define INVALIDATE(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer, error) \
 {\
-    INVALIDATE_(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer, error, SchemaValidator, Pointer) \
+    INVALIDATE_(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer, error, kValidateDefaultFlags, SchemaValidator, Pointer) \
 }
 
 #define INVALIDATE_(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer, error, \
-    SchemaValidatorType, PointerType) \
+    flags, SchemaValidatorType, PointerType) \
 {\
     SchemaValidatorType validator(schema);\
+    validator.SetValidateFlags(flags);\
     Document d;\
     /*printf("\n%s\n", json);*/\
     d.Parse(json);\
     EXPECT_FALSE(d.HasParseError());\
-    EXPECT_FALSE(d.Accept(validator));\
+    d.Accept(validator);\
     EXPECT_FALSE(validator.IsValid());\
+    ValidateErrorCode code = validator.GetInvalidSchemaCode();\
+    ASSERT_TRUE(code != kValidateErrorNone);\
+    ASSERT_TRUE(strcmp(GetValidateError_En(code), "Unknown error.") != 0);\
     if (validator.GetInvalidSchemaPointer() != PointerType(invalidSchemaPointer)) {\
         StringBuffer sb;\
         validator.GetInvalidSchemaPointer().Stringify(sb);\
@@ -191,6 +206,7 @@
     VALIDATE(s, "\"Life, the universe, and everything\"", true);
     INVALIDATE(s, "[\"Life\", \"the universe\", \"and everything\"]", "", "type", "",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": [\"string\", \"number\"], \"actual\": \"array\""
         "}}");
@@ -203,7 +219,7 @@
 
     VALIDATE(s, "\"red\"", true);
     INVALIDATE(s, "\"blue\"", "", "enum", "",
-        "{ \"enum\": { \"instanceRef\": \"#\", \"schemaRef\": \"#\" }}");
+        "{ \"enum\": { \"errorCode\": 19, \"instanceRef\": \"#\", \"schemaRef\": \"#\" }}");
 }
 
 TEST(SchemaValidator, Enum_Typless) {
@@ -215,7 +231,7 @@
     VALIDATE(s, "null", true);
     VALIDATE(s, "42", true);
     INVALIDATE(s, "0", "", "enum", "",
-        "{ \"enum\": { \"instanceRef\": \"#\", \"schemaRef\": \"#\" }}");
+        "{ \"enum\": { \"errorCode\": 19, \"instanceRef\": \"#\", \"schemaRef\": \"#\" }}");
 }
 
 TEST(SchemaValidator, Enum_InvalidType) {
@@ -226,6 +242,7 @@
     VALIDATE(s, "\"red\"", true);
     INVALIDATE(s, "null", "", "type", "",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": [\"string\"], \"actual\": \"null\""
         "}}");
@@ -239,9 +256,12 @@
 
         VALIDATE(s, "\"ok\"", true);
         INVALIDATE(s, "\"too long\"", "", "allOf", "",
-            "{ \"maxLength\": { "
-            "    \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/1\", "
-            "    \"expected\": 5, \"actual\": \"too long\""
+            "{ \"allOf\": {"
+            "    \"errors\": ["
+            "      {},"
+            "      {\"maxLength\": {\"errorCode\": 6, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/1\", \"expected\": 5, \"actual\": \"too long\"}}"
+            "    ],"
+            "    \"errorCode\": 23, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
             "}}");
     }
     {
@@ -251,8 +271,12 @@
 
         VALIDATE(s, "\"No way\"", false);
         INVALIDATE(s, "-1", "", "allOf", "",
-            "{ \"type\": { \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\","
-            "    \"expected\": [\"string\"], \"actual\": \"integer\""
+            "{ \"allOf\": {"
+            "    \"errors\": ["
+            "      {\"type\": { \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\", \"errorCode\": 20, \"expected\": [\"string\"], \"actual\": \"integer\"}},"
+            "      {}"
+            "    ],"
+            "    \"errorCode\": 23, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
             "}}");
     }
 }
@@ -266,13 +290,16 @@
     VALIDATE(s, "42", true);
     INVALIDATE(s, "{ \"Not a\": \"string or number\" }", "", "anyOf", "",
         "{ \"anyOf\": {"
+        "    \"errorCode\": 24,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\", "
         "    \"errors\": ["
         "      { \"type\": {"
+        "          \"errorCode\": 20,"
         "          \"instanceRef\": \"#\", \"schemaRef\": \"#/anyOf/0\","
         "          \"expected\": [\"string\"], \"actual\": \"object\""
         "      }},"
         "      { \"type\": {"
+        "          \"errorCode\": 20,"
         "          \"instanceRef\": \"#\", \"schemaRef\": \"#/anyOf/1\","
         "          \"expected\": [\"number\"], \"actual\": \"object\""
         "      }}"
@@ -289,20 +316,23 @@
     VALIDATE(s, "9", true);
     INVALIDATE(s, "2", "", "oneOf", "",
         "{ \"oneOf\": {"
+        "    \"errorCode\": 21,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"errors\": ["
         "      { \"multipleOf\": {"
+        "          \"errorCode\": 1,"
         "          \"instanceRef\": \"#\", \"schemaRef\": \"#/oneOf/0\","
         "          \"expected\": 5, \"actual\": 2"
         "      }},"
         "      { \"multipleOf\": {"
+        "          \"errorCode\": 1,"
         "          \"instanceRef\": \"#\", \"schemaRef\": \"#/oneOf/1\","
         "          \"expected\": 3, \"actual\": 2"
         "      }}"
         "    ]"
         "}}");
     INVALIDATE(s, "15", "", "oneOf", "",
-        "{ \"oneOf\": { \"instanceRef\": \"#\", \"schemaRef\": \"#\", \"errors\": [{}, {}]}}");
+        "{ \"oneOf\": { \"errorCode\": 22, \"instanceRef\": \"#\", \"schemaRef\": \"#\", \"errors\": [{}, {}]}}");
 }
 
 TEST(SchemaValidator, Not) {
@@ -313,7 +343,7 @@
     VALIDATE(s, "42", true);
     VALIDATE(s, "{ \"key\": \"value\" }", true);
     INVALIDATE(s, "\"I am a string\"", "", "not", "",
-        "{ \"not\": { \"instanceRef\": \"#\", \"schemaRef\": \"#\" }}");
+        "{ \"not\": { \"errorCode\": 25, \"instanceRef\": \"#\", \"schemaRef\": \"#\" }}");
 }
 
 TEST(SchemaValidator, Ref) {
@@ -378,10 +408,12 @@
     SchemaDocument s(sd);
 
     INVALIDATE(s, "{\"shipping_address\": {\"street_address\": \"1600 Pennsylvania Avenue NW\", \"city\": \"Washington\", \"state\": \"DC\"} }", "/properties/shipping_address", "allOf", "/shipping_address",
-        "{ \"required\": {"
-        "    \"instanceRef\": \"#/shipping_address\","
-        "    \"schemaRef\": \"#/properties/shipping_address/allOf/1\","
-        "    \"missing\": [\"type\"]"
+        "{ \"allOf\": {"
+        "    \"errors\": ["
+        "      {},"
+        "      {\"required\": {\"errorCode\": 15, \"instanceRef\": \"#/shipping_address\", \"schemaRef\": \"#/properties/shipping_address/allOf/1\", \"missing\": [\"type\"]}}"
+        "    ],"
+        "    \"errorCode\":23,\"instanceRef\":\"#/shipping_address\",\"schemaRef\":\"#/properties/shipping_address\""
         "}}");
     VALIDATE(s, "{\"shipping_address\": {\"street_address\": \"1600 Pennsylvania Avenue NW\", \"city\": \"Washington\", \"state\": \"DC\", \"type\": \"business\"} }", true);
 }
@@ -394,26 +426,31 @@
     VALIDATE(s, "\"I'm a string\"", true);
     INVALIDATE(s, "42", "", "type", "",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": [\"string\"], \"actual\": \"integer\""
         "}}");
     INVALIDATE(s, "2147483648", "", "type", "",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": [\"string\"], \"actual\": \"integer\""
         "}}"); // 2^31 can only be fit in unsigned
     INVALIDATE(s, "-2147483649", "", "type", "",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": [\"string\"], \"actual\": \"integer\""
         "}}"); // -2^31 - 1 can only be fit in int64_t
     INVALIDATE(s, "4294967296", "", "type", "",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": [\"string\"], \"actual\": \"integer\""
         "}}"); // 2^32 can only be fit in int64_t
     INVALIDATE(s, "3.1415926", "", "type", "",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": [\"string\"], \"actual\": \"number\""
         "}}");
@@ -426,6 +463,7 @@
 
     INVALIDATE(s, "\"A\"", "", "minLength", "",
         "{ \"minLength\": {"
+        "    \"errorCode\": 7,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 2, \"actual\": \"A\""
         "}}");
@@ -433,6 +471,7 @@
     VALIDATE(s, "\"ABC\"", true);
     INVALIDATE(s, "\"ABCD\"", "", "maxLength", "",
         "{ \"maxLength\": {"
+        "    \"errorCode\": 6,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 3, \"actual\": \"ABCD\""
         "}}");
@@ -448,11 +487,13 @@
     VALIDATE(s, "\"(888)555-1212\"", true);
     INVALIDATE(s, "\"(888)555-1212 ext. 532\"", "", "pattern", "",
         "{ \"pattern\": {"
+        "    \"errorCode\": 8,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"actual\": \"(888)555-1212 ext. 532\""
         "}}");
     INVALIDATE(s, "\"(800)FLOWERS\"", "", "pattern", "",
         "{ \"pattern\": {"
+        "    \"errorCode\": 8,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"actual\": \"(800)FLOWERS\""
         "}}");
@@ -482,11 +523,13 @@
     VALIDATE(s, "4294967296", true); // 2^32 can only be fit in int64_t
     INVALIDATE(s, "3.1415926", "", "type", "",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": [\"integer\"], \"actual\": \"number\""
         "}}");
     INVALIDATE(s, "\"42\"", "", "type", "",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": [\"integer\"], \"actual\": \"string\""
         "}}");
@@ -499,6 +542,7 @@
 
     INVALIDATE(s, "-1", "", "minimum", "",
         "{ \"minimum\": {"
+        "    \"errorCode\": 4,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 0, \"actual\": -1"
         "}}");
@@ -507,11 +551,13 @@
     VALIDATE(s, "99", true);
     INVALIDATE(s, "100", "", "maximum", "",
         "{ \"maximum\": {"
+        "    \"errorCode\": 3,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 100"
         "}}");
     INVALIDATE(s, "101", "", "maximum", "",
         "{ \"maximum\": {"
+        "    \"errorCode\": 3,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 101"
         "}}");
@@ -524,6 +570,7 @@
 
     INVALIDATE(s, "-9223372036854775808", "", "minimum", "",
         "{ \"minimum\": {"
+        "    \"errorCode\": 4,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": -9223372036854775807, \"actual\": -9223372036854775808"
         "}}");
@@ -536,11 +583,13 @@
     VALIDATE(s, "9223372036854775806", true);
     INVALIDATE(s, "9223372036854775807", "", "maximum", "",
         "{ \"maximum\": {"
+        "    \"errorCode\": 2,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 9223372036854775806, \"actual\": 9223372036854775807"
         "}}");
     INVALIDATE(s, "18446744073709551615", "", "maximum", "",
         "{ \"maximum\": {"
+        "    \"errorCode\": 2,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 9223372036854775806, \"actual\": 18446744073709551615"
         "}}");   // uint64_t max
@@ -553,36 +602,43 @@
 
     INVALIDATE(s, "-9223372036854775808", "", "minimum", "",
         "{ \"minimum\": {"
+        "    \"errorCode\": 4,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 9223372036854775808, \"actual\": -9223372036854775808"
         "}}");
     INVALIDATE(s, "9223372036854775807", "", "minimum", "",
         "{ \"minimum\": {"
+        "    \"errorCode\": 4,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 9223372036854775808, \"actual\": 9223372036854775807"
         "}}");
     INVALIDATE(s, "-2147483648", "", "minimum", "",
         "{ \"minimum\": {"
+        "    \"errorCode\": 4,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 9223372036854775808, \"actual\": -2147483648"
         "}}"); // int min
     INVALIDATE(s, "0", "", "minimum", "",
         "{ \"minimum\": {"
+        "    \"errorCode\": 4,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 9223372036854775808, \"actual\": 0"
         "}}");
     INVALIDATE(s, "2147483647", "", "minimum", "",
         "{ \"minimum\": {"
+        "    \"errorCode\": 4,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 9223372036854775808, \"actual\": 2147483647"
         "}}");  // int max
     INVALIDATE(s, "2147483648", "", "minimum", "",
         "{ \"minimum\": {"
+        "    \"errorCode\": 4,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 9223372036854775808, \"actual\": 2147483648"
         "}}");  // unsigned first
     INVALIDATE(s, "4294967295", "", "minimum", "",
         "{ \"minimum\": {"
+        "    \"errorCode\": 4,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 9223372036854775808, \"actual\": 4294967295"
         "}}");  // unsigned max
@@ -590,6 +646,7 @@
     VALIDATE(s, "18446744073709551614", true);
     INVALIDATE(s, "18446744073709551615", "", "maximum", "",
         "{ \"maximum\": {"
+        "    \"errorCode\": 2,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 18446744073709551614, \"actual\": 18446744073709551615"
         "}}");
@@ -602,6 +659,7 @@
 
     INVALIDATE(s, "-9223372036854775808", "", "minimum", "",
         "{ \"minimum\": {"
+        "    \"errorCode\": 5,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": -9223372036854775808, \"exclusiveMinimum\": true, "
         "    \"actual\": -9223372036854775808"
@@ -610,6 +668,7 @@
     VALIDATE(s, "18446744073709551614", true);
     INVALIDATE(s, "18446744073709551615", "", "maximum", "",
         "{ \"maximum\": {"
+        "    \"errorCode\": 3,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 18446744073709551615, \"exclusiveMaximum\": true, "
         "    \"actual\": 18446744073709551615"
@@ -627,11 +686,13 @@
     VALIDATE(s, "20", true);
     INVALIDATE(s, "23", "", "multipleOf", "",
         "{ \"multipleOf\": {"
+        "    \"errorCode\": 1,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 10, \"actual\": 23"
         "}}");
     INVALIDATE(s, "-23", "", "multipleOf", "",
         "{ \"multipleOf\": {"
+        "    \"errorCode\": 1,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 10, \"actual\": -23"
         "}}");
@@ -646,6 +707,7 @@
     VALIDATE(s, "18446744073709551615", true);
     INVALIDATE(s, "18446744073709551614", "", "multipleOf", "",
         "{ \"multipleOf\": {"
+        "    \"errorCode\": 1,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 18446744073709551615, \"actual\": 18446744073709551614"
         "}}");
@@ -658,6 +720,7 @@
 
     INVALIDATE(s, "-1", "", "minimum", "",
         "{ \"minimum\": {"
+        "    \"errorCode\": 4,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 0, \"actual\": -1"
         "}}");
@@ -668,16 +731,19 @@
     VALIDATE(s, "99.9", true);
     INVALIDATE(s, "100", "", "maximum", "",
         "{ \"maximum\": {"
+        "    \"errorCode\": 3,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 100"
         "}}");
     INVALIDATE(s, "100.0", "", "maximum", "",
         "{ \"maximum\": {"
+        "    \"errorCode\": 3,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 100.0"
         "}}");
     INVALIDATE(s, "101.5", "", "maximum", "",
         "{ \"maximum\": {"
+        "    \"errorCode\": 3,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 101.5"
         "}}");
@@ -690,11 +756,13 @@
 
     INVALIDATE(s, "-101", "", "minimum", "",
         "{ \"minimum\": {"
+        "    \"errorCode\": 4,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": -100, \"actual\": -101"
         "}}");
     INVALIDATE(s, "-100.1", "", "minimum", "",
         "{ \"minimum\": {"
+        "    \"errorCode\": 4,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": -100, \"actual\": -100.1"
         "}}");
@@ -702,46 +770,55 @@
     VALIDATE(s, "-2", true);
     INVALIDATE(s, "-1", "", "maximum", "",
         "{ \"maximum\": {"
+        "    \"errorCode\": 3,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": -1"
         "}}");
     INVALIDATE(s, "-0.9", "", "maximum", "",
         "{ \"maximum\": {"
+        "    \"errorCode\": 3,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": -0.9"
         "}}");
     INVALIDATE(s, "0", "", "maximum", "",
         "{ \"maximum\": {"
+        "    \"errorCode\": 3,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 0"
         "}}");
     INVALIDATE(s, "2147483647", "", "maximum", "",
         "{ \"maximum\": {"
+        "    \"errorCode\": 3,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 2147483647"
         "}}");  // int max
     INVALIDATE(s, "2147483648", "", "maximum", "",
         "{ \"maximum\": {"
+        "    \"errorCode\": 3,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 2147483648"
         "}}");  // unsigned first
     INVALIDATE(s, "4294967295", "", "maximum", "",
         "{ \"maximum\": {"
+        "    \"errorCode\": 3,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 4294967295"
         "}}");  // unsigned max
     INVALIDATE(s, "9223372036854775808", "", "maximum", "",
         "{ \"maximum\": {"
+        "    \"errorCode\": 3,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 9223372036854775808"
         "}}");
     INVALIDATE(s, "18446744073709551614", "", "maximum", "",
         "{ \"maximum\": {"
+        "    \"errorCode\": 3,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551614"
         "}}");
     INVALIDATE(s, "18446744073709551615", "", "maximum", "",
         "{ \"maximum\": {"
+        "    \"errorCode\": 3,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551615"
         "}}");
@@ -754,16 +831,19 @@
 
     INVALIDATE(s, "-9223372036854775808", "", "minimum", "",
         "{ \"minimum\": {"
+        "    \"errorCode\": 4,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 0.1, \"actual\": -9223372036854775808"
         "}}");
     INVALIDATE(s, "-2147483648", "", "minimum", "",
         "{ \"minimum\": {"
+        "    \"errorCode\": 4,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 0.1, \"actual\": -2147483648"
         "}}"); // int min
     INVALIDATE(s, "-1", "", "minimum", "",
         "{ \"minimum\": {"
+        "    \"errorCode\": 4,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 0.1, \"actual\": -1"
         "}}");
@@ -773,51 +853,61 @@
     VALIDATE(s, "100", true);
     INVALIDATE(s, "101", "", "maximum", "",
         "{ \"maximum\": {"
+        "    \"errorCode\": 3,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 101"
         "}}");
     INVALIDATE(s, "101.5", "", "maximum", "",
         "{ \"maximum\": {"
+        "    \"errorCode\": 3,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 101.5"
         "}}");
     INVALIDATE(s, "18446744073709551614", "", "maximum", "",
         "{ \"maximum\": {"
+        "    \"errorCode\": 3,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551614"
         "}}");
     INVALIDATE(s, "18446744073709551615", "", "maximum", "",
         "{ \"maximum\": {"
+        "    \"errorCode\": 3,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551615"
         "}}");
     INVALIDATE(s, "2147483647", "", "maximum", "",
         "{ \"maximum\": {"
+        "    \"errorCode\": 3,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 2147483647"
         "}}");  // int max
     INVALIDATE(s, "2147483648", "", "maximum", "",
         "{ \"maximum\": {"
+        "    \"errorCode\": 3,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 2147483648"
         "}}");  // unsigned first
     INVALIDATE(s, "4294967295", "", "maximum", "",
         "{ \"maximum\": {"
+        "    \"errorCode\": 3,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 4294967295"
         "}}");  // unsigned max
     INVALIDATE(s, "9223372036854775808", "", "maximum", "",
         "{ \"maximum\": {"
+        "    \"errorCode\": 3,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 9223372036854775808"
         "}}");
     INVALIDATE(s, "18446744073709551614", "", "maximum", "",
         "{ \"maximum\": {"
+        "    \"errorCode\": 3,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551614"
         "}}");
     INVALIDATE(s, "18446744073709551615", "", "maximum", "",
         "{ \"maximum\": {"
+        "    \"errorCode\": 3,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551615"
         "}}");
@@ -830,31 +920,37 @@
 
     INVALIDATE(s, "-9223372036854775808", "", "minimum", "",
         "{ \"minimum\": {"
+        "    \"errorCode\": 4,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 9223372036854775808.0, \"actual\": -9223372036854775808"
         "}}");
     INVALIDATE(s, "-2147483648", "", "minimum", "",
         "{ \"minimum\": {"
+        "    \"errorCode\": 4,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 9223372036854775808.0, \"actual\": -2147483648"
         "}}"); // int min
     INVALIDATE(s, "0", "", "minimum", "",
         "{ \"minimum\": {"
+        "    \"errorCode\": 4,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 9223372036854775808.0, \"actual\": 0"
         "}}");
     INVALIDATE(s, "2147483647", "", "minimum", "",
         "{ \"minimum\": {"
+        "    \"errorCode\": 4,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 9223372036854775808.0, \"actual\": 2147483647"
         "}}");  // int max
     INVALIDATE(s, "2147483648", "", "minimum", "",
         "{ \"minimum\": {"
+        "    \"errorCode\": 4,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 9223372036854775808.0, \"actual\": 2147483648"
         "}}");  // unsigned first
     INVALIDATE(s, "4294967295", "", "minimum", "",
         "{ \"minimum\": {"
+        "    \"errorCode\": 4,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 9223372036854775808.0, \"actual\": 4294967295"
         "}}");  // unsigned max
@@ -862,6 +958,7 @@
     VALIDATE(s, "18446744073709540000", true);
     INVALIDATE(s, "18446744073709551615", "", "maximum", "",
         "{ \"maximum\": {"
+        "    \"errorCode\": 2,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 18446744073709550000.0, \"actual\": 18446744073709551615"
         "}}");
@@ -878,28 +975,33 @@
     VALIDATE(s, "20", true);
     INVALIDATE(s, "23", "", "multipleOf", "",
         "{ \"multipleOf\": {"
+        "    \"errorCode\": 1,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 10.0, \"actual\": 23"
         "}}");
     INVALIDATE(s, "-2147483648", "", "multipleOf", "",
         "{ \"multipleOf\": {"
+        "    \"errorCode\": 1,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 10.0, \"actual\": -2147483648"
         "}}");  // int min
     VALIDATE(s, "-2147483640", true);
     INVALIDATE(s, "2147483647", "", "multipleOf", "",
         "{ \"multipleOf\": {"
+        "    \"errorCode\": 1,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 10.0, \"actual\": 2147483647"
         "}}");  // int max
     INVALIDATE(s, "2147483648", "", "multipleOf", "",
         "{ \"multipleOf\": {"
+        "    \"errorCode\": 1,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 10.0, \"actual\": 2147483648"
         "}}");  // unsigned first
     VALIDATE(s, "2147483650", true);
     INVALIDATE(s, "4294967295", "", "multipleOf", "",
         "{ \"multipleOf\": {"
+        "    \"errorCode\": 1,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 10.0, \"actual\": 4294967295"
         "}}");  // unsigned max
@@ -915,6 +1017,7 @@
     VALIDATE(s, "42.0", true);
     INVALIDATE(s, "3.1415926", "", "multipleOf", "",
         "{ \"multipleOf\": {"
+        "    \"errorCode\": 1,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 1, \"actual\": 3.1415926"
         "}}");
@@ -929,11 +1032,13 @@
     VALIDATE(s, "{\"Sun\":1.9891e30,\"Jupiter\":1.8986e27,\"Saturn\":5.6846e26,\"Neptune\":10.243e25,\"Uranus\":8.6810e25,\"Earth\":5.9736e24,\"Venus\":4.8685e24,\"Mars\":6.4185e23,\"Mercury\":3.3022e23,\"Moon\":7.349e22,\"Pluto\":1.25e22}", true);    
     INVALIDATE(s, "[\"An\", \"array\", \"not\", \"an\", \"object\"]", "", "type", "",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": [\"object\"], \"actual\": \"array\""
         "}}");
     INVALIDATE(s, "\"Not an object\"", "", "type", "",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": [\"object\"], \"actual\": \"string\""
         "}}");
@@ -956,12 +1061,14 @@
     VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", true);
     INVALIDATE(s, "{ \"number\": \"1600\", \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", "/properties/number", "type", "/number",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#/number\", \"schemaRef\": \"#/properties/number\","
         "    \"expected\": [\"number\"], \"actual\": \"string\""
         "}}");
     INVALIDATE(s, "{ \"number\": \"One\", \"street_name\": \"Microsoft\", \"street_type\": \"Way\" }",
         "/properties/number", "type", "/number",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#/number\", \"schemaRef\": \"#/properties/number\","
         "    \"expected\": [\"number\"], \"actual\": \"string\""
         "}}"); // fail fast
@@ -990,6 +1097,7 @@
     VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", true);
     INVALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"direction\": \"NW\" }", "", "additionalProperties", "/direction",
         "{ \"additionalProperties\": {"
+        "    \"errorCode\": 16,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"disallowed\": \"direction\""
         "}}");
@@ -1015,6 +1123,7 @@
     VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"direction\": \"NW\" }", true);
     INVALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"office_number\": 201 }", "/additionalProperties", "type", "/office_number",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#/office_number\", \"schemaRef\": \"#/additionalProperties\","
         "    \"expected\": [\"string\"], \"actual\": \"integer\""
         "}}");
@@ -1039,11 +1148,13 @@
     VALIDATE(s, "{ \"name\": \"William Shakespeare\", \"email\" : \"bill@stratford-upon-avon.co.uk\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\", \"authorship\" : \"in question\"}", true);
     INVALIDATE(s, "{ \"name\": \"William Shakespeare\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\" }", "", "required", "",
         "{ \"required\": {"
+        "    \"errorCode\": 15,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"missing\": [\"email\"]"
         "}}");
     INVALIDATE(s, "{}", "", "required", "",
         "{ \"required\": {"
+        "    \"errorCode\": 15,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"missing\": [\"name\", \"email\"]"
         "}}");
@@ -1067,11 +1178,13 @@
     VALIDATE(s, "{ \"email\" : \"bill@stratford-upon-avon.co.uk\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\", \"authorship\" : \"in question\"}", true);
     INVALIDATE(s, "{ \"name\": \"William Shakespeare\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\" }", "", "required", "",
         "{ \"required\": {"
+        "    \"errorCode\": 15,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"missing\": [\"email\"]"
         "}}");
     INVALIDATE(s, "{}", "", "required", "",
         "{ \"required\": {"
+        "    \"errorCode\": 15,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"missing\": [\"email\"]"
         "}}");
@@ -1084,11 +1197,13 @@
 
     INVALIDATE(s, "{}", "", "minProperties", "",
         "{ \"minProperties\": {"
+        "    \"errorCode\": 14,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 2, \"actual\": 0"
         "}}");
     INVALIDATE(s, "{\"a\":0}", "", "minProperties", "",
         "{ \"minProperties\": {"
+        "    \"errorCode\": 14,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 2, \"actual\": 1"
         "}}");
@@ -1096,6 +1211,7 @@
     VALIDATE(s, "{\"a\":0,\"b\":1,\"c\":2}", true);
     INVALIDATE(s, "{\"a\":0,\"b\":1,\"c\":2,\"d\":3}", "", "maxProperties", "",
         "{ \"maxProperties\": {"
+        "    \"errorCode\": 13,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\", "
         "    \"expected\": 3, \"actual\": 4"
         "}}");
@@ -1123,8 +1239,15 @@
         "\"billing_address\": \"555 Debtor's Lane\" }", true);
     INVALIDATE(s, "{ \"name\": \"John Doe\", \"credit_card\": 5555555555555555 }", "", "dependencies", "",
         "{ \"dependencies\": {"
+        "    \"errorCode\": 18,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
-        "    \"errors\": {\"credit_card\": [\"cvv_code\", \"billing_address\"]}"
+        "    \"errors\": {"
+        "       \"credit_card\": {"
+        "        \"required\": {"
+        "          \"errorCode\": 15,"
+        "          \"instanceRef\": \"#\", \"schemaRef\": \"#/dependencies/credit_card\","
+        "          \"missing\": [\"cvv_code\", \"billing_address\"]"
+        "    } } }"
         "}}");
     VALIDATE(s, "{ \"name\": \"John Doe\"}", true);
     VALIDATE(s, "{ \"name\": \"John Doe\", \"cvv_code\": 777, \"billing_address\": \"555 Debtor's Lane\" }", true);
@@ -1154,10 +1277,12 @@
     VALIDATE(s, "{\"name\": \"John Doe\", \"credit_card\" : 5555555555555555,\"billing_address\" : \"555 Debtor's Lane\"}", true);
     INVALIDATE(s, "{\"name\": \"John Doe\", \"credit_card\" : 5555555555555555 }", "", "dependencies", "",
         "{ \"dependencies\": {"
+        "    \"errorCode\": 18,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"errors\": {"
         "      \"credit_card\": {"
         "        \"required\": {"
+        "          \"errorCode\": 15,"
         "          \"instanceRef\": \"#\", \"schemaRef\": \"#/dependencies/credit_card\","
         "          \"missing\": [\"billing_address\"]"
         "    } } }"
@@ -1182,18 +1307,20 @@
     VALIDATE(s, "{ \"I_0\": 42 }", true);
     INVALIDATE(s, "{ \"S_0\": 42 }", "", "patternProperties", "/S_0",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#/S_0\", \"schemaRef\": \"#/patternProperties/%5ES_\","
         "    \"expected\": [\"string\"], \"actual\": \"integer\""
         "}}");
     INVALIDATE(s, "{ \"I_42\": \"This is a string\" }", "", "patternProperties", "/I_42",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#/I_42\", \"schemaRef\": \"#/patternProperties/%5EI_\","
         "    \"expected\": [\"integer\"], \"actual\": \"string\""
         "}}");
     VALIDATE(s, "{ \"keyword\": \"value\" }", true);
 }
 
-TEST(SchemaValidator, Object_PattternProperties_ErrorConflict) {
+TEST(SchemaValidator, Object_PatternProperties_ErrorConflict) {
     Document sd;
     sd.Parse(
         "{"
@@ -1209,9 +1336,11 @@
     INVALIDATE(s, "{ \"I_30\": 7 }", "", "patternProperties", "/I_30",
         "{ \"multipleOf\": ["
         "    {"
+        "      \"errorCode\": 1,"
         "      \"instanceRef\": \"#/I_30\", \"schemaRef\": \"#/patternProperties/%5EI_\","
         "      \"expected\": 5, \"actual\": 7"
         "    }, {"
+        "      \"errorCode\": 1,"
         "      \"instanceRef\": \"#/I_30\", \"schemaRef\": \"#/patternProperties/30%24\","
         "      \"expected\": 6, \"actual\": 7"
         "    }"
@@ -1236,22 +1365,25 @@
     VALIDATE(s, "{ \"I_42\": 78 }", true);
     INVALIDATE(s, "{ \"I_42\": 42 }", "", "patternProperties", "/I_42",
         "{ \"minimum\": {"
+        "    \"errorCode\": 4,"
         "    \"instanceRef\": \"#/I_42\", \"schemaRef\": \"#/properties/I_42\","
         "    \"expected\": 73, \"actual\": 42"
         "}}");
     INVALIDATE(s, "{ \"I_42\": 7 }", "", "patternProperties", "/I_42",
         "{ \"minimum\": {"
+        "    \"errorCode\": 4,"
         "    \"instanceRef\": \"#/I_42\", \"schemaRef\": \"#/properties/I_42\","
         "    \"expected\": 73, \"actual\": 7"
         "  },"
         "  \"multipleOf\": {"
+        "    \"errorCode\": 1,"
         "    \"instanceRef\": \"#/I_42\", \"schemaRef\": \"#/patternProperties/%5EI_\","
         "    \"expected\": 6, \"actual\": 7"
         "  }"
         "}");
 }
 
-TEST(SchemaValidator, Object_PatternProperties_AdditionalProperties) {
+TEST(SchemaValidator, Object_PatternProperties_AdditionalPropertiesObject) {
     Document sd;
     sd.Parse(
         "{"
@@ -1271,10 +1403,35 @@
     VALIDATE(s, "{ \"keyword\": \"value\" }", true);
     INVALIDATE(s, "{ \"keyword\": 42 }", "/additionalProperties", "type", "/keyword",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#/keyword\", \"schemaRef\": \"#/additionalProperties\","
         "    \"expected\": [\"string\"], \"actual\": \"integer\""
         "}}");
 }
+
+// Replaces test Issue285 and tests failure as well as success
+TEST(SchemaValidator, Object_PatternProperties_AdditionalPropertiesBoolean) {
+    Document sd;
+    sd.Parse(
+        "{"
+        "  \"type\": \"object\","
+        "  \"patternProperties\": {"
+        "    \"^S_\": { \"type\": \"string\" },"
+        "    \"^I_\": { \"type\": \"integer\" }"
+        "  },"
+        "  \"additionalProperties\": false"
+        "}");
+    SchemaDocument s(sd);
+
+    VALIDATE(s, "{ \"S_25\": \"This is a string\" }", true);
+    VALIDATE(s, "{ \"I_0\": 42 }", true);
+    INVALIDATE(s, "{ \"keyword\": \"value\" }", "", "additionalProperties", "/keyword",
+        "{ \"additionalProperties\": {"
+        "    \"errorCode\": 16,"
+        "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+        "    \"disallowed\": \"keyword\""
+        "}}");
+}
 #endif
 
 TEST(SchemaValidator, Array) {
@@ -1286,6 +1443,7 @@
     VALIDATE(s, "[3, \"different\", { \"types\" : \"of values\" }]", true);
     INVALIDATE(s, "{\"Not\": \"an array\"}", "", "type", "",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": [\"array\"], \"actual\": \"object\""
         "}}");
@@ -1305,6 +1463,7 @@
     VALIDATE(s, "[1, 2, 3, 4, 5]", true);
     INVALIDATE(s, "[1, 2, \"3\", 4, 5]", "/items", "type", "/2",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#/2\", \"schemaRef\": \"#/items\","
         "    \"expected\": [\"number\"], \"actual\": \"string\""
         "}}");
@@ -1337,14 +1496,16 @@
 
     VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\"]", true);
     INVALIDATE(s, "[24, \"Sussex\", \"Drive\"]", "/items/2", "enum", "/2",
-        "{ \"enum\": { \"instanceRef\": \"#/2\", \"schemaRef\": \"#/items/2\" }}");
+        "{ \"enum\": { \"errorCode\": 19, \"instanceRef\": \"#/2\", \"schemaRef\": \"#/items/2\" }}");
     INVALIDATE(s, "[\"Palais de l'Elysee\"]", "/items/0", "type", "/0",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#/0\", \"schemaRef\": \"#/items/0\","
         "    \"expected\": [\"number\"], \"actual\": \"string\""
         "}}");
     INVALIDATE(s, "[\"Twenty-four\", \"Sussex\", \"Drive\"]", "/items/0", "type", "/0",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#/0\", \"schemaRef\": \"#/items/0\","
         "    \"expected\": [\"number\"], \"actual\": \"string\""
         "}}"); // fail fast
@@ -1352,7 +1513,7 @@
     VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\", \"Washington\"]", true);
 }
 
-TEST(SchemaValidator, Array_AdditionalItmes) {
+TEST(SchemaValidator, Array_AdditionalItems) {
     Document sd;
     sd.Parse(
         "{"
@@ -1379,8 +1540,9 @@
 
     VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\"]", true);
     VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\"]", true);
-    INVALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\", \"Washington\"]", "", "items", "/4",
+    INVALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\", \"Washington\"]", "", "additionalItems", "/4",
         "{ \"additionalItems\": {"
+        "    \"errorCode\": 12,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"disallowed\": 4"
         "}}");
@@ -1393,11 +1555,13 @@
 
     INVALIDATE(s, "[]", "", "minItems", "",
         "{ \"minItems\": {"
+        "    \"errorCode\": 10,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 2, \"actual\": 0"
         "}}");
     INVALIDATE(s, "[1]", "", "minItems", "",
         "{ \"minItems\": {"
+        "    \"errorCode\": 10,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 2, \"actual\": 1"
         "}}");
@@ -1405,6 +1569,7 @@
     VALIDATE(s, "[1, 2, 3]", true);
     INVALIDATE(s, "[1, 2, 3, 4]", "", "maxItems", "",
         "{ \"maxItems\": {"
+        "    \"errorCode\": 9,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 3, \"actual\": 4"
         "}}");
@@ -1418,11 +1583,13 @@
     VALIDATE(s, "[1, 2, 3, 4, 5]", true);
     INVALIDATE(s, "[1, 2, 3, 3, 4]", "", "uniqueItems", "/3",
         "{ \"uniqueItems\": {"
+        "    \"errorCode\": 11,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"duplicates\": [2, 3]"
         "}}");
     INVALIDATE(s, "[1, 2, 3, 3, 3]", "", "uniqueItems", "/3",
         "{ \"uniqueItems\": {"
+        "    \"errorCode\": 11,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"duplicates\": [2, 3]"
         "}}"); // fail fast
@@ -1438,11 +1605,13 @@
     VALIDATE(s, "false", true);
     INVALIDATE(s, "\"true\"", "", "type", "",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": [\"boolean\"], \"actual\": \"string\""
         "}}");
     INVALIDATE(s, "0", "", "type", "",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": [\"boolean\"], \"actual\": \"integer\""
         "}}");
@@ -1456,16 +1625,19 @@
     VALIDATE(s, "null", true);
     INVALIDATE(s, "false", "", "type", "",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": [\"null\"], \"actual\": \"boolean\""
         "}}");
     INVALIDATE(s, "0", "", "type", "",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": [\"null\"], \"actual\": \"integer\""
         "}}");
     INVALIDATE(s, "\"\"", "", "type", "",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": [\"null\"], \"actual\": \"string\""
         "}}");
@@ -1481,11 +1653,13 @@
     VALIDATE(s, "[\"a\"]", true);
     INVALIDATE(s, "[1]", "/items", "type", "/0",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#/0\", \"schemaRef\": \"#/items\","
         "    \"expected\": [\"string\"], \"actual\": \"integer\""
         "}}");
     INVALIDATE(s, "[{}]", "/items", "type", "/0",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#/0\", \"schemaRef\": \"#/items\","
         "    \"expected\": [\"string\"], \"actual\": \"object\""
         "}}");
@@ -1508,6 +1682,7 @@
     VALIDATE(s, "{ \"tel\": \"123-456\" }", true);
     INVALIDATE(s, "{ \"tel\": true }", "/properties/tel", "type", "/tel",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#/tel\", \"schemaRef\": \"#/properties/tel\","
         "    \"expected\": [\"string\", \"integer\"], \"actual\": \"boolean\""
         "}}");
@@ -1530,6 +1705,7 @@
     VALIDATE(s, "{ \"tel\": 999 }", true);
     INVALIDATE(s, "{ \"tel\": \"fail\" }", "/properties/tel", "type", "/tel",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#/tel\", \"schemaRef\": \"#/properties/tel\","
         "    \"expected\": [\"integer\"], \"actual\": \"string\""
         "}}");
@@ -1550,48 +1726,71 @@
     VALIDATE(s, "\"ok\"", true);
     VALIDATE(s, "\"OK\"", true);
     INVALIDATE(s, "\"okay\"", "", "allOf", "",
-        "{ \"enum\": {"
-        "    \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\""
+        "{ \"allOf\": {"
+        "    \"errors\": ["
+        "    {},{},"
+        "    { \"allOf\": {"
+        "      \"errors\": ["
+        "        {},"
+        "        { \"enum\": {\"errorCode\": 19, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\" }}"
+        "      ],"
+        "      \"errorCode\": 23, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2\""
+        "    }}],"
+        "    \"errorCode\": 23, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
         "}}");
     INVALIDATE(s, "\"o\"", "", "allOf", "",
-        "{ \"minLength\": {"
-        "    \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\","
-        "    \"expected\": 2, \"actual\": \"o\""
+        "{ \"allOf\": {"
+        "  \"errors\": ["
+        "    { \"minLength\": {\"actual\": \"o\", \"expected\": 2, \"errorCode\": 7, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\" }},"
+        "    {},{}"
+        "  ],"
+        "  \"errorCode\": 23, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
         "}}");
     INVALIDATE(s, "\"n\"", "", "allOf", "",
-        "{ \"minLength\": {"
-        "    \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\","
-        "    \"expected\": 2, \"actual\": \"n\""
-        "  },"
-        "  \"enum\": ["
-        "    {\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/0\"},"
-        "    {\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"}"
-        "  ]"
-        "}")
+        "{ \"allOf\": {"
+        "    \"errors\": ["
+        "      { \"minLength\": {\"actual\": \"n\", \"expected\": 2, \"errorCode\": 7, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\" }},"
+        "      {},"
+        "      { \"allOf\": {"
+        "          \"errors\": ["
+        "            { \"enum\": {\"errorCode\": 19 ,\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/0\"}},"
+        "            { \"enum\": {\"errorCode\": 19, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"}}"
+        "          ],"
+        "          \"errorCode\": 23, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2\""
+        "      }}"
+        "    ],"
+        "    \"errorCode\":23,\"instanceRef\":\"#\",\"schemaRef\":\"#\""
+        "}}");
     INVALIDATE(s, "\"too long\"", "", "allOf", "",
-        "{ \"maxLength\": {"
-        "    \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/1\","
-        "    \"expected\": 5, \"actual\": \"too long\""
-        "  },"
-        "  \"enum\": ["
-        "    {\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/0\"},"
-        "    {\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"}"
-        "  ]"
-        "}");
+        "{ \"allOf\": {"
+        "    \"errors\": ["
+        "      {},"
+        "      { \"maxLength\": {\"actual\": \"too long\", \"expected\": 5, \"errorCode\": 6, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/1\" }},"
+        "      { \"allOf\": {"
+        "          \"errors\": ["
+        "            { \"enum\": {\"errorCode\": 19 ,\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/0\"}},"
+        "            { \"enum\": {\"errorCode\": 19, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"}}"
+        "          ],"
+        "          \"errorCode\": 23, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2\""
+        "      }}"
+        "    ],"
+        "    \"errorCode\":23,\"instanceRef\":\"#\",\"schemaRef\":\"#\""
+        "}}");
     INVALIDATE(s, "123", "", "allOf", "",
-        "{ \"type\": ["
-        "    { \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\","
-        "      \"expected\": [\"string\"], \"actual\": \"integer\""
-        "    },"
-        "    { \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/1\","
-        "      \"expected\": [\"string\"], \"actual\": \"integer\""
-        "    }"
-        "  ],"
-        "  \"enum\": ["
-        "    {\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/0\"},"
-        "    {\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"}"
-        "  ]"
-        "}");
+        "{ \"allOf\": {"
+        "    \"errors\": ["
+        "      {\"type\": {\"expected\": [\"string\"], \"actual\": \"integer\", \"errorCode\": 20, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\"}},"
+        "      {\"type\": {\"expected\": [\"string\"], \"actual\": \"integer\", \"errorCode\": 20, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/1\"}},"
+        "      { \"allOf\": {"
+        "          \"errors\": ["
+        "            { \"enum\": {\"errorCode\": 19 ,\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/0\"}},"
+        "            { \"enum\": {\"errorCode\": 19, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"}}"
+        "          ],"
+        "          \"errorCode\": 23, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2\""
+        "      }}"
+        "    ],"
+        "    \"errorCode\":23,\"instanceRef\":\"#\",\"schemaRef\":\"#\""
+        "}}");
 }
 
 TEST(SchemaValidator, EscapedPointer) {
@@ -1606,6 +1805,7 @@
     SchemaDocument s(sd);
     INVALIDATE(s, "{\"~/\":true}", "/properties/~0~1", "type", "/~0~1",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#/~0~1\", \"schemaRef\": \"#/properties/~0~1\","
         "    \"expected\": [\"number\"], \"actual\": \"boolean\""
         "}}");
@@ -1650,11 +1850,14 @@
     ASSERT_FALSE(d.HasParseError());
     SchemaDocument sd(d);
     SchemaValidator validator(sd);
-    if (!d.Accept(validator)) {
+    d.Accept(validator);
+    if (!validator.IsValid()) {
         StringBuffer sb;
         validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
         printf("Invalid schema: %s\n", sb.GetString());
         printf("Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());
+        printf("Invalid code: %d\n", validator.GetInvalidSchemaCode());
+        printf("Invalid message: %s\n", GetValidateError_En(validator.GetInvalidSchemaCode()));
         sb.Clear();
         validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
         printf("Invalid document: %s\n", sb.GetString());
@@ -1681,7 +1884,8 @@
     ASSERT_FALSE(d.HasParseError());
     SD sd(d);
     SV validator(sd);
-    if (!d.Accept(validator)) {
+    d.Accept(validator);
+    if (!validator.IsValid()) {
         GenericStringBuffer<UTF16<> > sb;
         validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
         wprintf(L"Invalid schema: %ls\n", sb.GetString());
@@ -1709,13 +1913,15 @@
             "jsonschema/remotes/integer.json",
             "jsonschema/remotes/subSchemas.json",
             "jsonschema/remotes/folder/folderInteger.json",
-            "draft-04/schema"
+            "draft-04/schema",
+            "unittestschema/address.json"
         };
         const char* uris[kCount] = {
             "http://localhost:1234/integer.json",
             "http://localhost:1234/subSchemas.json",
             "http://localhost:1234/folder/folderInteger.json",
-            "http://json-schema.org/draft-04/schema"
+            "http://json-schema.org/draft-04/schema",
+            "http://localhost:1234/address.json"
         };
 
         for (size_t i = 0; i < kCount; i++) {
@@ -1757,7 +1963,7 @@
     RemoteSchemaDocumentProvider(const RemoteSchemaDocumentProvider&);
     RemoteSchemaDocumentProvider& operator=(const RemoteSchemaDocumentProvider&);
 
-    static const size_t kCount = 4;
+    static const size_t kCount = 5;
     SchemaDocumentType* sd_[kCount];
     typename DocumentType::AllocatorType documentAllocator_;
     typename SchemaDocumentType::AllocatorType schemaAllocator_;
@@ -1826,6 +2032,7 @@
             ADD_FAILURE();
         }
         else {
+            //printf("json test suite file %s parsed ok\n", filename);
             GenericDocument<UTF8<>, MemoryPoolAllocator<>, MemoryPoolAllocator<> > d(&documentAllocator, 1024, &documentStackAllocator);
             d.Parse(json);
             if (d.HasParseError()) {
@@ -1846,11 +2053,14 @@
                                 bool expected = (*testItr)["valid"].GetBool();
                                 testCount++;
                                 validator.Reset();
-                                bool actual = data.Accept(validator);
+                                data.Accept(validator);
+                                bool actual = validator.IsValid();
                                 if (expected != actual)
                                     printf("Fail: %30s \"%s\" \"%s\"\n", filename, description1, description2);
-                                else
+                                else {
+                                    //printf("Passed: %30s \"%s\" \"%s\"\n", filename, description1, description2);
                                     passCount++;
+                                }
                             }
                         }
                         //printf("%zu %zu %zu\n", documentAllocator.Size(), schemaAllocator.Size(), validatorAllocator.Size());
@@ -1865,8 +2075,8 @@
         jsonAllocator.Clear();
     }
     printf("%d / %d passed (%2d%%)\n", passCount, testCount, passCount * 100 / testCount);
-    // if (passCount != testCount)
-    //     ADD_FAILURE();
+//    if (passCount != testCount)
+//        ADD_FAILURE();
 }
 
 TEST(SchemaValidatingReader, Simple) {
@@ -1897,12 +2107,14 @@
     EXPECT_FALSE(reader.IsValid());
     EXPECT_EQ(kParseErrorTermination, reader.GetParseResult().Code());
     EXPECT_STREQ("maxLength", reader.GetInvalidSchemaKeyword());
+    EXPECT_TRUE(reader.GetInvalidSchemaCode() == kValidateErrorMaxLength);
     EXPECT_TRUE(reader.GetInvalidSchemaPointer() == SchemaDocument::PointerType(""));
     EXPECT_TRUE(reader.GetInvalidDocumentPointer() == SchemaDocument::PointerType(""));
     EXPECT_TRUE(d.IsNull());
     Document e;
     e.Parse(
         "{ \"maxLength\": {"
+"            \"errorCode\": 6,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 3, \"actual\": \"ABCD\""
         "}}");
@@ -1933,9 +2145,11 @@
     EXPECT_FALSE(validator.IsValid());
     EXPECT_TRUE(validator.GetInvalidSchemaPointer() == SchemaDocument::PointerType(""));
     EXPECT_TRUE(validator.GetInvalidDocumentPointer() == SchemaDocument::PointerType(""));
+    EXPECT_TRUE(validator.GetInvalidSchemaCode() == kValidateErrorMaxLength);
     Document e;
     e.Parse(
         "{ \"maxLength\": {"
+"            \"errorCode\": 6,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": 3, \"actual\": \"ABCD\""
         "}}");
@@ -1963,6 +2177,7 @@
     VALIDATE(s, "\"Life, the universe, and everything\"", true);
     INVALIDATE(s, "[\"Life\", \"the universe\", \"and everything\"]", "", "type", "",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"expected\": [\"string\", \"number\"], \"actual\": \"array\""
         "}}");
@@ -1978,6 +2193,7 @@
     VALIDATE(s, "{\"a\" : null, \"b\": null}", true);
     INVALIDATE(s, "{\"a\" : null, \"a\" : null}", "", "required", "",
         "{ \"required\": {"
+        "    \"errorCode\": 15,"
         "    \"instanceRef\": \"#\", \"schemaRef\": \"#\","
         "    \"missing\": [\"b\"]"
         "}}");
@@ -1991,13 +2207,6 @@
     VALIDATE(s, "{\"key1\": \"abc\", \"key2\": \"def\"}", true);
 }
 
-TEST(SchemaValidator, Issue825) {
-    Document sd;
-    sd.Parse("{\"type\": \"object\", \"additionalProperties\": false, \"patternProperties\": {\"^i\": { \"type\": \"string\" } } }");
-    SchemaDocument s(sd);
-    VALIDATE(s, "{ \"item\": \"hello\" }", true);
-}
-
 TEST(SchemaValidator, Issue1017_allOfHandler) {
     Document sd;
     sd.Parse("{\"allOf\": [{\"type\": \"object\",\"properties\": {\"cyanArray2\": {\"type\": \"array\",\"items\": { \"type\": \"string\" }}}},{\"type\": \"object\",\"properties\": {\"blackArray\": {\"type\": \"array\",\"items\": { \"type\": \"string\" }}},\"required\": [ \"blackArray\" ]}]}");
@@ -2027,19 +2236,25 @@
     typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
     INVALIDATE_(s, "null", "/integer", "type", "",
         "{ \"type\": {"
+        "    \"errorCode\": 20,"
         "    \"instanceRef\": \"#\","
         "    \"schemaRef\": \"http://localhost:1234/subSchemas.json#/integer\","
         "    \"expected\": [\"integer\"], \"actual\": \"null\""
         "}}",
-        SchemaValidatorType, PointerType);
+        kValidateDefaultFlags, SchemaValidatorType, PointerType);
 }
 
 TEST(SchemaValidator, Ref_remote_issue1210) {
     class SchemaDocumentProvider : public IRemoteSchemaDocumentProvider {
         SchemaDocument** collection;
 
-        SchemaDocumentProvider(const SchemaDocumentProvider&);
-        SchemaDocumentProvider& operator=(const SchemaDocumentProvider&);
+        // Dummy private copy constructor & assignment operator.
+        // Function bodies added so that they compile in MSVC 2019.
+        SchemaDocumentProvider(const SchemaDocumentProvider&) : collection(NULL) {
+        }
+        SchemaDocumentProvider& operator=(const SchemaDocumentProvider&) {
+            return *this;
+        }
 
         public:
           SchemaDocumentProvider(SchemaDocument** collection) : collection(collection) { }
@@ -2067,6 +2282,306 @@
     VALIDATE(sx, "{\"country\":\"US\"}", true);
 }
 
+// Test that when kValidateContinueOnErrorFlag is set, all errors are reported.
+TEST(SchemaValidator, ContinueOnErrors) {
+    CrtAllocator allocator;
+    char* schema = ReadFile("unittestschema/address.json", allocator);
+    Document sd;
+    sd.Parse(schema);
+    ASSERT_FALSE(sd.HasParseError());
+    SchemaDocument s(sd);
+    VALIDATE(s, "{\"version\": 1.0, \"address\": {\"number\": 24, \"street1\": \"The Woodlands\", \"street3\": \"Ham\", \"city\": \"Romsey\", \"area\": \"Kent\", \"country\": \"UK\", \"postcode\": \"SO51 0GP\"}, \"phones\": [\"0111-222333\", \"0777-666888\"], \"names\": [\"Fred\", \"Bloggs\"]}", true);
+    INVALIDATE_(s, "{\"version\": 1.01, \"address\": {\"number\": 0, \"street2\": false,  \"street3\": \"Ham\", \"city\": \"RomseyTownFC\", \"area\": \"BC\", \"country\": \"USA\", \"postcode\": \"999ABC\"}, \"phones\": [], \"planet\": \"Earth\", \"extra\": {\"S_xxx\": 123}}", "#", "errors", "#",
+        "{ \"multipleOf\": {"
+        "    \"errorCode\": 1, \"instanceRef\": \"#/version\", \"schemaRef\": \"#/definitions/decimal_type\", \"expected\": 1.0, \"actual\": 1.01"
+        "  },"
+        "  \"minimum\": {"
+        "    \"errorCode\": 5, \"instanceRef\": \"#/address/number\", \"schemaRef\": \"#/definitions/positiveInt_type\", \"expected\": 0, \"actual\": 0, \"exclusiveMinimum\": true"
+        "  },"
+        "  \"type\": ["
+        "    {\"expected\": [\"null\", \"string\"], \"actual\": \"boolean\", \"errorCode\": 20, \"instanceRef\": \"#/address/street2\", \"schemaRef\": \"#/definitions/address_type/properties/street2\"},"
+        "    {\"expected\": [\"string\"], \"actual\": \"integer\", \"errorCode\": 20, \"instanceRef\": \"#/extra/S_xxx\", \"schemaRef\": \"#/properties/extra/patternProperties/%5ES_\"}"
+        "  ],"
+        "  \"maxLength\": {"
+        "    \"actual\": \"RomseyTownFC\", \"expected\": 10, \"errorCode\": 6, \"instanceRef\": \"#/address/city\", \"schemaRef\": \"#/definitions/address_type/properties/city\""
+        "  },"
+        "  \"anyOf\": {"
+        "    \"errors\":["
+        "      {\"pattern\": {\"actual\": \"999ABC\", \"errorCode\": 8, \"instanceRef\": \"#/address/postcode\", \"schemaRef\": \"#/definitions/address_type/properties/postcode/anyOf/0\"}},"
+        "      {\"pattern\": {\"actual\": \"999ABC\", \"errorCode\": 8, \"instanceRef\": \"#/address/postcode\", \"schemaRef\": \"#/definitions/address_type/properties/postcode/anyOf/1\"}}"
+        "    ],"
+        "    \"errorCode\": 24, \"instanceRef\": \"#/address/postcode\", \"schemaRef\": \"#/definitions/address_type/properties/postcode\""
+        "  },"
+        "  \"allOf\": {"
+        "    \"errors\":["
+        "      {\"enum\":{\"errorCode\":19,\"instanceRef\":\"#/address/country\",\"schemaRef\":\"#/definitions/country_type\"}}"
+        "    ],"
+        "    \"errorCode\":23,\"instanceRef\":\"#/address/country\",\"schemaRef\":\"#/definitions/address_type/properties/country\""
+        "  },"
+        "  \"minItems\": {"
+        "    \"actual\": 0, \"expected\": 1, \"errorCode\": 10, \"instanceRef\": \"#/phones\", \"schemaRef\": \"#/properties/phones\""
+        "  },"
+        "  \"additionalProperties\": {"
+        "    \"disallowed\": \"planet\", \"errorCode\": 16, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
+        "  },"
+        "  \"required\": {"
+        "    \"missing\": [\"street1\"], \"errorCode\": 15, \"instanceRef\": \"#/address\", \"schemaRef\": \"#/definitions/address_type\""
+        "  }"
+        "}",
+        kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+    INVALIDATE_(s, "{\"address\": {\"number\": 200, \"street1\": {}, \"street3\": null, \"city\": \"Rom\", \"area\": \"Dorset\", \"postcode\": \"SO51 0GP\"}, \"phones\": [\"0111-222333\", \"0777-666888\", \"0777-666888\"], \"names\": [\"Fred\", \"S\", \"M\", \"Bloggs\"]}", "#", "errors", "#",
+        "{ \"maximum\": {"
+        "    \"errorCode\": 3, \"instanceRef\": \"#/address/number\", \"schemaRef\": \"#/definitions/positiveInt_type\", \"expected\": 100, \"actual\": 200, \"exclusiveMaximum\": true"
+        "  },"
+        "  \"type\": {"
+        "    \"expected\": [\"string\"], \"actual\": \"object\", \"errorCode\": 20, \"instanceRef\": \"#/address/street1\", \"schemaRef\": \"#/definitions/address_type/properties/street1\""
+        "  },"
+        "  \"not\": {"
+        "    \"errorCode\": 25, \"instanceRef\": \"#/address/street3\", \"schemaRef\": \"#/definitions/address_type/properties/street3\""
+        "  },"
+        "  \"minLength\": {"
+        "    \"actual\": \"Rom\", \"expected\": 4, \"errorCode\": 7, \"instanceRef\": \"#/address/city\", \"schemaRef\": \"#/definitions/address_type/properties/city\""
+        "  },"
+        "  \"maxItems\": {"
+        "    \"actual\": 3, \"expected\": 2, \"errorCode\": 9, \"instanceRef\": \"#/phones\", \"schemaRef\": \"#/properties/phones\""
+        "  },"
+        "  \"uniqueItems\": {"
+        "    \"duplicates\": [1, 2], \"errorCode\": 11, \"instanceRef\": \"#/phones\", \"schemaRef\": \"#/properties/phones\""
+        "  },"
+        "  \"minProperties\": {\"actual\": 6, \"expected\": 7, \"errorCode\": 14, \"instanceRef\": \"#/address\", \"schemaRef\": \"#/definitions/address_type\""
+        "  },"
+        "  \"additionalItems\": ["
+        "    {\"disallowed\": 2, \"errorCode\": 12, \"instanceRef\": \"#/names\", \"schemaRef\": \"#/properties/names\"},"
+        "    {\"disallowed\": 3, \"errorCode\": 12, \"instanceRef\": \"#/names\", \"schemaRef\": \"#/properties/names\"}"
+        "  ],"
+        "  \"dependencies\": {"
+        "    \"errors\": {"
+        "      \"address\": {\"required\": {\"missing\": [\"version\"], \"errorCode\": 15, \"instanceRef\": \"#\", \"schemaRef\": \"#/dependencies/address\"}},"
+        "      \"names\": {\"required\": {\"missing\": [\"version\"], \"errorCode\": 15, \"instanceRef\": \"#\", \"schemaRef\": \"#/dependencies/names\"}}"
+        "    },"
+        "    \"errorCode\": 18, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
+        "  },"
+        "  \"oneOf\": {"
+        "    \"errors\": ["
+        "      {\"enum\": {\"errorCode\": 19, \"instanceRef\": \"#/address/area\", \"schemaRef\": \"#/definitions/county_type\"}},"
+        "      {\"enum\": {\"errorCode\": 19, \"instanceRef\": \"#/address/area\", \"schemaRef\": \"#/definitions/province_type\"}}"
+        "    ],"
+        "    \"errorCode\": 21, \"instanceRef\": \"#/address/area\", \"schemaRef\": \"#/definitions/address_type/properties/area\""
+        "  }"
+        "}",
+        kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+
+        CrtAllocator::Free(schema);
+}
+
+// Test that when kValidateContinueOnErrorFlag is set, it is not propagated to oneOf sub-validator so we only get the first error.
+TEST(SchemaValidator, ContinueOnErrors_OneOf) {
+    typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+    RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+    CrtAllocator allocator;
+    char* schema = ReadFile("unittestschema/oneOf_address.json", allocator);
+    Document sd;
+    sd.Parse(schema);
+    ASSERT_FALSE(sd.HasParseError());
+    SchemaDocumentType s(sd, 0, 0, &provider);
+    typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
+    typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+    INVALIDATE_(s, "{\"version\": 1.01, \"address\": {\"number\": 0, \"street2\": false,  \"street3\": \"Ham\", \"city\": \"RomseyTownFC\", \"area\": \"BC\", \"country\": \"USA\", \"postcode\": \"999ABC\"}, \"phones\": [], \"planet\": \"Earth\", \"extra\": {\"S_xxx\": 123}}", "#", "errors", "#",
+        "{ \"oneOf\": {"
+        "    \"errors\": [{"
+        "      \"multipleOf\": {"
+        "        \"errorCode\": 1, \"instanceRef\": \"#/version\", \"schemaRef\": \"http://localhost:1234/address.json#/definitions/decimal_type\", \"expected\": 1.0, \"actual\": 1.01"
+        "      }"
+        "    }],"
+        "    \"errorCode\": 21, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
+        "  }"
+        "}",
+        kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidatorType, PointerType);
+    CrtAllocator::Free(schema);
+}
+
+// Test that when kValidateContinueOnErrorFlag is set, it is not propagated to allOf sub-validator so we only get the first error.
+TEST(SchemaValidator, ContinueOnErrors_AllOf) {
+    typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+    RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+    CrtAllocator allocator;
+    char* schema = ReadFile("unittestschema/allOf_address.json", allocator);
+    Document sd;
+    sd.Parse(schema);
+    ASSERT_FALSE(sd.HasParseError());
+    SchemaDocumentType s(sd, 0, 0, &provider);
+    typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
+    typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+    INVALIDATE_(s, "{\"version\": 1.01, \"address\": {\"number\": 0, \"street2\": false,  \"street3\": \"Ham\", \"city\": \"RomseyTownFC\", \"area\": \"BC\", \"country\": \"USA\", \"postcode\": \"999ABC\"}, \"phones\": [], \"planet\": \"Earth\", \"extra\": {\"S_xxx\": 123}}", "#", "errors", "#",
+        "{ \"allOf\": {"
+        "    \"errors\": [{"
+        "      \"multipleOf\": {"
+        "        \"errorCode\": 1, \"instanceRef\": \"#/version\", \"schemaRef\": \"http://localhost:1234/address.json#/definitions/decimal_type\", \"expected\": 1.0, \"actual\": 1.01"
+        "      }"
+        "    }],"
+        "    \"errorCode\": 23, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
+        "  }"
+        "}",
+        kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidatorType, PointerType);
+    CrtAllocator::Free(schema);
+}
+
+// Test that when kValidateContinueOnErrorFlag is set, it is not propagated to anyOf sub-validator so we only get the first error.
+TEST(SchemaValidator, ContinueOnErrors_AnyOf) {
+    typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+    RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+    CrtAllocator allocator;
+    char* schema = ReadFile("unittestschema/anyOf_address.json", allocator);
+    Document sd;
+    sd.Parse(schema);
+    ASSERT_FALSE(sd.HasParseError());
+    SchemaDocumentType s(sd, 0, 0, &provider);
+    typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
+    typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+    INVALIDATE_(s, "{\"version\": 1.01, \"address\": {\"number\": 0, \"street2\": false,  \"street3\": \"Ham\", \"city\": \"RomseyTownFC\", \"area\": \"BC\", \"country\": \"USA\", \"postcode\": \"999ABC\"}, \"phones\": [], \"planet\": \"Earth\", \"extra\": {\"S_xxx\": 123}}", "#", "errors", "#",
+        "{ \"anyOf\": {"
+        "    \"errors\": [{"
+        "      \"multipleOf\": {"
+        "        \"errorCode\": 1, \"instanceRef\": \"#/version\", \"schemaRef\": \"http://localhost:1234/address.json#/definitions/decimal_type\", \"expected\": 1.0, \"actual\": 1.01"
+        "      }"
+        "    }],"
+        "    \"errorCode\": 24, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
+        "  }"
+        "}",
+        kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidatorType, PointerType);
+
+    CrtAllocator::Free(schema);
+}
+
+// Test that when kValidateContinueOnErrorFlag is set, arrays with uniqueItems:true are correctly processed when an item is invalid.
+// This tests that we don't blow up if a hasher does not get created.
+TEST(SchemaValidator, ContinueOnErrors_UniqueItems) {
+    CrtAllocator allocator;
+    char* schema = ReadFile("unittestschema/address.json", allocator);
+    Document sd;
+    sd.Parse(schema);
+    ASSERT_FALSE(sd.HasParseError());
+    SchemaDocument s(sd);
+    VALIDATE(s, "{\"phones\":[\"12-34\",\"56-78\"]}", true);
+    INVALIDATE_(s, "{\"phones\":[\"12-34\",\"12-34\"]}", "#", "errors", "#",
+        "{\"uniqueItems\": {\"duplicates\": [0,1], \"errorCode\": 11, \"instanceRef\": \"#/phones\", \"schemaRef\": \"#/properties/phones\"}}",
+        kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+    INVALIDATE_(s, "{\"phones\":[\"ab-34\",\"cd-78\"]}", "#", "errors", "#",
+        "{\"pattern\": ["
+        "  {\"actual\": \"ab-34\", \"errorCode\": 8, \"instanceRef\": \"#/phones/0\", \"schemaRef\": \"#/definitions/phone_type\"},"
+        "  {\"actual\": \"cd-78\", \"errorCode\": 8, \"instanceRef\": \"#/phones/1\", \"schemaRef\": \"#/definitions/phone_type\"}"
+        "]}",
+        kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+    CrtAllocator::Free(schema);
+}
+
+// Test that when kValidateContinueOnErrorFlag is set, an enum field is correctly processed when it has an invalid value.
+// This tests that we don't blow up if a hasher does not get created.
+TEST(SchemaValidator, ContinueOnErrors_Enum) {
+    CrtAllocator allocator;
+    char* schema = ReadFile("unittestschema/address.json", allocator);
+    Document sd;
+    sd.Parse(schema);
+    ASSERT_FALSE(sd.HasParseError());
+    SchemaDocument s(sd);
+    VALIDATE(s, "{\"gender\":\"M\"}", true);
+    INVALIDATE_(s, "{\"gender\":\"X\"}", "#", "errors", "#",
+        "{\"enum\": {\"errorCode\": 19, \"instanceRef\": \"#/gender\", \"schemaRef\": \"#/properties/gender\"}}",
+        kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+    INVALIDATE_(s, "{\"gender\":1}", "#", "errors", "#",
+        "{\"type\": {\"expected\":[\"string\"], \"actual\": \"integer\", \"errorCode\": 20, \"instanceRef\": \"#/gender\", \"schemaRef\": \"#/properties/gender\"}}",
+        kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+    CrtAllocator::Free(schema);
+}
+
+// Test that when kValidateContinueOnErrorFlag is set, an array appearing for an object property is handled
+// This tests that we don't blow up when there is a type mismatch.
+TEST(SchemaValidator, ContinueOnErrors_RogueArray) {
+    CrtAllocator allocator;
+    char* schema = ReadFile("unittestschema/address.json", allocator);
+    Document sd;
+    sd.Parse(schema);
+    ASSERT_FALSE(sd.HasParseError());
+    SchemaDocument s(sd);
+    INVALIDATE_(s, "{\"address\":[{\"number\": 0}]}", "#", "errors", "#",
+        "{\"type\": {\"expected\":[\"object\"], \"actual\": \"array\", \"errorCode\": 20, \"instanceRef\": \"#/address\", \"schemaRef\": \"#/definitions/address_type\"},"
+        "  \"dependencies\": {"
+        "    \"errors\": {"
+        "      \"address\": {\"required\": {\"missing\": [\"version\"], \"errorCode\": 15, \"instanceRef\": \"#\", \"schemaRef\": \"#/dependencies/address\"}}"
+        "    },\"errorCode\": 18, \"instanceRef\": \"#\", \"schemaRef\": \"#\"}}",
+        kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+    CrtAllocator::Free(schema);
+}
+
+// Test that when kValidateContinueOnErrorFlag is set, an object appearing for an array property is handled
+// This tests that we don't blow up when there is a type mismatch.
+TEST(SchemaValidator, ContinueOnErrors_RogueObject) {
+    CrtAllocator allocator;
+    char* schema = ReadFile("unittestschema/address.json", allocator);
+    Document sd;
+    sd.Parse(schema);
+    ASSERT_FALSE(sd.HasParseError());
+    SchemaDocument s(sd);
+    INVALIDATE_(s, "{\"phones\":{\"number\": 0}}", "#", "errors", "#",
+        "{\"type\": {\"expected\":[\"array\"], \"actual\": \"object\", \"errorCode\": 20, \"instanceRef\": \"#/phones\", \"schemaRef\": \"#/properties/phones\"}}",
+        kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+    CrtAllocator::Free(schema);
+}
+
+// Test that when kValidateContinueOnErrorFlag is set, a string appearing for an array or object property is handled
+// This tests that we don't blow up when there is a type mismatch.
+TEST(SchemaValidator, ContinueOnErrors_RogueString) {
+    CrtAllocator allocator;
+    char* schema = ReadFile("unittestschema/address.json", allocator);
+    Document sd;
+    sd.Parse(schema);
+    ASSERT_FALSE(sd.HasParseError());
+    SchemaDocument s(sd);
+    INVALIDATE_(s, "{\"address\":\"number\"}", "#", "errors", "#",
+        "{\"type\": {\"expected\":[\"object\"], \"actual\": \"string\", \"errorCode\": 20, \"instanceRef\": \"#/address\", \"schemaRef\": \"#/definitions/address_type\"},"
+        "  \"dependencies\": {"
+        "    \"errors\": {"
+        "      \"address\": {\"required\": {\"missing\": [\"version\"], \"errorCode\": 15, \"instanceRef\": \"#\", \"schemaRef\": \"#/dependencies/address\"}}"
+        "    },\"errorCode\": 18, \"instanceRef\": \"#\", \"schemaRef\": \"#\"}}",
+        kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+    INVALIDATE_(s, "{\"phones\":\"number\"}", "#", "errors", "#",
+        "{\"type\": {\"expected\":[\"array\"], \"actual\": \"string\", \"errorCode\": 20, \"instanceRef\": \"#/phones\", \"schemaRef\": \"#/properties/phones\"}}",
+        kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+    CrtAllocator::Free(schema);
+}
+
+// Test that when kValidateContinueOnErrorFlag is set, an incorrect simple type with a sub-schema is handled correctly.
+// This tests that we don't blow up when there is a type mismatch but there is a sub-schema present
+TEST(SchemaValidator, ContinueOnErrors_Issue2) {
+    Document sd;
+    sd.Parse("{\"type\":\"string\", \"anyOf\":[{\"maxLength\":2}]}");
+    ASSERT_FALSE(sd.HasParseError());
+    SchemaDocument s(sd);
+    VALIDATE(s, "\"AB\"", true);
+    INVALIDATE_(s, "\"ABC\"", "#", "errors", "#",
+        "{ \"anyOf\": {"
+        "    \"errors\": [{"
+        "      \"maxLength\": {"
+        "        \"errorCode\": 6, \"instanceRef\": \"#\", \"schemaRef\": \"#/anyOf/0\", \"expected\": 2, \"actual\": \"ABC\""
+        "      }"
+        "    }],"
+        "    \"errorCode\": 24, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
+        "  }"
+        "}",
+        kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+    // Invalid type
+    INVALIDATE_(s, "333", "#", "errors", "#",
+        "{ \"type\": {"
+        "    \"errorCode\": 20, \"instanceRef\": \"#\", \"schemaRef\": \"#\", \"expected\": [\"string\"], \"actual\": \"integer\""
+        "  }"
+        "}",
+        kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+}
+
+TEST(SchemaValidator, Schema_UnknownError) {
+    ASSERT_TRUE(SchemaValidator::SchemaType::GetValidateErrorKeyword(kValidateErrors).GetString() == std::string("null"));
+}
+
 #if defined(_MSC_VER) || defined(__clang__)
 RAPIDJSON_DIAG_POP
 #endif
diff --git a/test/unittest/simdtest.cpp b/test/unittest/simdtest.cpp
index c60c85b..649505f 100644
--- a/test/unittest/simdtest.cpp
+++ b/test/unittest/simdtest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/unittest/strfunctest.cpp b/test/unittest/strfunctest.cpp
index cc1bb22..4112693 100644
--- a/test/unittest/strfunctest.cpp
+++ b/test/unittest/strfunctest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/unittest/stringbuffertest.cpp b/test/unittest/stringbuffertest.cpp
index 2e36442..eaa29e7 100644
--- a/test/unittest/stringbuffertest.cpp
+++ b/test/unittest/stringbuffertest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/unittest/strtodtest.cpp b/test/unittest/strtodtest.cpp
index 807f887..66167a4 100644
--- a/test/unittest/strtodtest.cpp
+++ b/test/unittest/strtodtest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/unittest/unittest.cpp b/test/unittest/unittest.cpp
index b754563..879976a 100644
--- a/test/unittest/unittest.cpp
+++ b/test/unittest/unittest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/unittest/unittest.h b/test/unittest/unittest.h
index 0afac09..0e64d39 100644
--- a/test/unittest/unittest.h
+++ b/test/unittest/unittest.h
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp
index 4a16f7d..00f0652 100644
--- a/test/unittest/valuetest.cpp
+++ b/test/unittest/valuetest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at
diff --git a/test/unittest/writertest.cpp b/test/unittest/writertest.cpp
index 232b03d..ac9ad89 100644
--- a/test/unittest/writertest.cpp
+++ b/test/unittest/writertest.cpp
@@ -1,6 +1,6 @@
 // Tencent is pleased to support the open source community by making RapidJSON available.
 // 
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
 //
 // Licensed under the MIT License (the "License"); you may not use this file except
 // in compliance with the License. You may obtain a copy of the License at