diff --git a/Sources/KiteJSONValidator.h b/Sources/KiteJSONValidator.h
index b94ddcf..4923e29 100644
--- a/Sources/KiteJSONValidator.h
+++ b/Sources/KiteJSONValidator.h
@@ -20,11 +20,12 @@
  
  @param jsonData The JSON to be validated
  @param schemaData The draft4 JSON schema to validate against
- @return Whether the json is validated.
+ @return Error if json is invalid. Nil if validated
  */
--(BOOL)validateJSONData:(NSData*)jsonData withSchemaData:(NSData*)schemaData;
--(BOOL)validateJSONInstance:(id)json withSchema:(NSDictionary*)schema;
--(BOOL)validateJSONInstance:(id)json withSchemaData:(NSData*)schemaData;
+
+-(NSError*)validateJSONData:(NSData*)jsonData withSchemaData:(NSData*)schemaData;
+-(NSError*)validateJSONInstance:(id)json withSchema:(NSDictionary*)schema;
+-(NSError*)validateJSONInstance:(id)json withSchemaData:(NSData*)schemaData;
 //TODO:add an interface to add a schema with a key, allowing a schema to only be validated once and then reused
 
 /**
@@ -33,9 +34,9 @@
  @param schemaData The data for the document to be converted to JSON
  @param url        The fragmentless URL for this document
  
- @return Whether the reference schema was successfully added.
+ @return Error if the reference schema is invalid. Nil if was successfully added.
  */
--(BOOL)addRefSchemaData:(NSData*)schemaData atURL:(NSURL*)url;
+-(NSError*)addRefSchemaData:(NSData*)schemaData atURL:(NSURL*)url;
 
 /**
  Used for adding an ENTIRE document to the list of reference schemas - the URL should therefore be fragmentless.
@@ -44,9 +45,10 @@
  @param url                  The fragmentless URL for this document
  @param shouldValidateSchema Whether the new reference schema should be validated against the "root" schema.
  
- @return Whether the reference schema was successfully added.
+ 
+ @return Error if the reference schema is invalid. Nil if was successfully added.
  */
--(BOOL)addRefSchemaData:(NSData*)schemaData atURL:(NSURL*)url validateSchema:(BOOL)shouldValidateSchema;
+-(NSError*)addRefSchemaData:(NSData*)schemaData atURL:(NSURL*)url validateSchema:(BOOL)shouldValidateSchema;
 
 /**
  Used for adding an ENTIRE document to the list of reference schemas - the URL should therefore be fragmentless.
@@ -54,9 +56,9 @@
  @param schema The dictionary representation of the JSON schema (the JSON was therefore valid).
  @param url    The fragmentless URL for this document
  
- @return Whether the reference schema was successfully added.
+ @return Error if the reference schema is invalid. Nil if was successfully added.
  */
--(BOOL)addRefSchema:(NSDictionary*)schema atURL:(NSURL*)url;
+-(NSError*)addRefSchema:(NSDictionary*)schema atURL:(NSURL*)url;
 
 /**
  Used for adding an ENTIRE document to the list of reference schemas - the URL should therefore be fragmentless.
@@ -65,9 +67,9 @@
  @param url                  The fragmentless URL for this document
  @param shouldValidateSchema Whether the new reference schema should be validated against the "root" schema.
  
- @return Whether the reference schema was successfully added.
+ @return Error if the reference schema is invalid. Nil if was successfully added.
  */
--(BOOL)addRefSchema:(NSDictionary *)schema atURL:(NSURL *)url validateSchema:(BOOL)shouldValidateSchema;
+-(NSError*)addRefSchema:(NSDictionary *)schema atURL:(NSURL *)url validateSchema:(BOOL)shouldValidateSchema;
 
 @end
 
diff --git a/Sources/KiteJSONValidator.m b/Sources/KiteJSONValidator.m
index fdca952..25872a2 100644
--- a/Sources/KiteJSONValidator.m
+++ b/Sources/KiteJSONValidator.m
@@ -18,6 +18,18 @@ @interface KiteJSONValidator()
 
 @end
 
+NSError* ValidationError(NSString* path, NSString* format, ...){
+
+    static NSString* KiteJSONValidatorDomain = @"KiteJSONValidator";
+    
+    va_list args;
+    va_start(args, format);
+    NSString* description = [[NSString alloc] initWithFormat:format arguments:args];
+    va_end(args);
+    
+    return [NSError errorWithDomain:KiteJSONValidatorDomain code:0 userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"%@ %@ %@", path, (path.length ? @":" : @""), description]}];
+}
+
 @implementation KiteJSONValidator
 
 @synthesize validationStack=_validationStack;
@@ -33,85 +45,83 @@ -(id)init
     if (self) {
         NSURL *rootURL = [NSURL URLWithString:@"http://json-schema.org/draft-04/schema#"];
         NSDictionary *rootSchema = [self rootSchema];
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunused-variable"
-        BOOL success = [self addRefSchema:rootSchema atURL:rootURL validateSchema:NO];
-#pragma clang diagnostic pop
-        NSAssert(success == YES, @"Unable to add the root schema!", nil);
+        NSAssert([self addRefSchema:rootSchema atURL:rootURL validateSchema:NO]==nil, @"Unable to add the root schema!", nil);
     }
 
     return self;
 }
 
--(BOOL)addRefSchema:(NSDictionary *)schema atURL:(NSURL *)url validateSchema:(BOOL)shouldValidateSchema
+-(NSError*)addRefSchema:(NSDictionary *)schema atURL:(NSURL *)url validateSchema:(BOOL)shouldValidateSchema
 {
     NSError * error;
     //We convert to data in order to protect ourselves against a cyclic structure and ensure we have valid JSON
     NSData * schemaData = [NSJSONSerialization dataWithJSONObject:schema options:0 error:&error];
-    if (error != nil) {
-        return NO;
+    if (error) {
+        return error;
     }
     return [self addRefSchemaData:schemaData atURL:url validateSchema:shouldValidateSchema];
 }
 
--(BOOL)addRefSchema:(NSDictionary*)schema atURL:(NSURL*)url
+-(NSError*)addRefSchema:(NSDictionary*)schema atURL:(NSURL*)url
 {
     return [self addRefSchema:schema atURL:url validateSchema:YES];
 }
 
--(BOOL)addRefSchemaData:(NSData *)schemaData atURL:(NSURL *)url
+-(NSError*)addRefSchemaData:(NSData *)schemaData atURL:(NSURL *)url
 {
     return [self addRefSchemaData:schemaData atURL:url validateSchema:YES];
 }
 
--(BOOL)addRefSchemaData:(NSData*)schemaData atURL:(NSURL*)url validateSchema:(BOOL)shouldValidateSchema
+-(NSMutableDictionary *)schemaRefs
+{
+    if (!_schemaRefs){
+        _schemaRefs = [NSMutableDictionary dictionary];
+    }
+    return _schemaRefs;
+}
+
+-(NSError*)addRefSchemaData:(NSData*)schemaData atURL:(NSURL*)url validateSchema:(BOOL)shouldValidateSchema
 {
+    if (!url) {
+        return ValidationError(@"", @"URL MUST not be empty");
+    }
+    
     if (!schemaData || ![schemaData isKindOfClass:[NSData class]]) {
-        return NO;
+        return ValidationError(@"", @"Data MUST be NSData class. Not %@", schemaData.class);
     }
     
     NSError * error = nil;
     id schema = [NSJSONSerialization JSONObjectWithData:schemaData options:0 error:&error];
-    if (error != nil) {
-        return NO;
+    if (error) {
+        return error;
     } else if (![schema isKindOfClass:[NSDictionary class]]) {
-        return NO;
+        return ValidationError(@"", @"Schema MUST be an 'object'. Not %@", [schema class]);
     }
-    
-    NSAssert(url != NULL, @"URL must not be empty", nil);
-    NSAssert(schema != NULL, @"Schema must not be empty", nil);
-    
-    if (!url || !schema)
-    {
-        //NSLog(@"Invalid schema for URL (%@): %@", url, schema);
-        return NO;
+
+    if (!schema) {
+        return ValidationError(@"", @"Schema MUST not be empty");
     }
+    
     url = [self urlWithoutFragment:url];
     //TODO:consider failing if the url contained a fragment.
     
-    if (shouldValidateSchema)
-    {
+    if (shouldValidateSchema) {
         NSDictionary *root = [self rootSchema];
-        if (![root isEqualToDictionary:schema])
-        {
-            BOOL isValidSchema = [self validateJSON:schema withSchemaDict:root];
-            NSAssert(isValidSchema == YES, @"Invalid schema", nil);
-            if (!isValidSchema) return NO;
+        if (![root isEqualToDictionary:schema]) {
+            NSError* schemaError = [self validateJSON:schema withSchemaDict:root];
+            if (schemaError) {
+                return ValidationError(@"", @"Invalid schema: %@", schemaError.localizedDescription);
+            }
         }
-        else
-        {
+        else {
             //NSLog(@"Can't really validate the root schema against itself, right? ... Right?");
         }
     }
     
     @synchronized(self)
     {
-        if (!_schemaRefs)
-        {
-            _schemaRefs = [[NSMutableDictionary alloc] init];
-        }
         self.schemaRefs[url] = schema;
-        return YES;
+        return nil;
     }
 }
 
@@ -128,9 +138,7 @@ -(NSDictionary *)rootSchema
 
         NSData *rootSchemaData = [NSData dataWithContentsOfFile:rootSchemaPath];
         NSError *error = nil;
-        rootSchema = [NSJSONSerialization JSONObjectWithData:rootSchemaData
-                                                     options:kNilOptions
-                                                       error:&error];
+        rootSchema = [NSJSONSerialization JSONObjectWithData:rootSchemaData options:0 error:&error];
         NSAssert(rootSchema != NULL, @"Root schema wasn't found", nil);
         NSAssert([rootSchema isKindOfClass:[NSDictionary class]], @"Root schema wasn't a dictionary", nil);
     });
@@ -138,19 +146,38 @@ -(NSDictionary *)rootSchema
     return rootSchema;
 }
 
--(BOOL)pushToStackJSON:(id)json forSchema:(NSDictionary*)schema
+-(NSMutableArray *)validationStack
 {
-    if (self.validationStack == nil) {
-        self.validationStack = [NSMutableArray new];
-        self.resolutionStack = [NSMutableArray new];
-        self.schemaStack = [NSMutableArray new];
+    if (!_validationStack) {
+        _validationStack = [NSMutableArray array];
     }
+    return _validationStack;
+}
+
+-(NSMutableArray *)resolutionStack
+{
+    if (!_resolutionStack) {
+        _resolutionStack = [NSMutableArray array];
+    }
+    return _resolutionStack;
+}
+
+-(NSMutableArray *)schemaStack
+{
+    if (!_schemaStack) {
+        _schemaStack = [NSMutableArray array];
+    }
+    return _schemaStack;
+}
+
+-(NSError*)pushToStackJSON:(id)json forSchema:(NSDictionary*)schema
+{
     KiteValidationPair * pair = [KiteValidationPair pairWithLeft:json right:schema];
     if ([self.validationStack containsObject:pair]) {
-        return NO; //Detects loops
+        return ValidationError(@"", @"Loops detectsed"); //Detects loops
     }
     [self.validationStack addObject:pair];
-    return YES;
+    return nil;
 }
 
 -(void)popStack
@@ -177,12 +204,11 @@ -(NSURL*)urlWithoutFragment:(NSURL*)url
     return [NSURL URLWithString:refString];
 }
 
--(BOOL)validateJSON:(id)json withSchemaAtReference:(NSString*)refString
+-(NSError*)validateJSON:(id)json withSchemaAtReference:(NSString*)refString path:( NSString* )path
 {
     NSURL * refURI = [NSURL URLWithString:refString relativeToURL:self.resolutionStack.lastObject];
-    if (!refURI)
-    {
-        return NO;
+    if (!refURI) {
+        return ValidationError(path ,@"No Ref URI for '%@'", refString);
     }
 
     //get the fragment, if it is a JSON-Pointer
@@ -208,7 +234,7 @@ -(BOOL)validateJSON:(id)json withSchemaAtReference:(NSString*)refString
     }
 
     if (!schema) {
-        return NO;
+        return ValidationError(path, @"No schema for Ref URI: %@", refURI);
     }
 
     for (NSString * component in pointerComponents) {
@@ -228,14 +254,14 @@ -(BOOL)validateJSON:(id)json withSchemaAtReference:(NSString*)refString
         }
 
         if (!schema) {
-            return NO;
+            return ValidationError(path, @"No schema");
         }
     }
-    BOOL result = [self _validateJSON:json withSchemaDict:schema];
+    NSError* error = [self _validateJSON:json withSchemaDict:schema path:path];
     if (newDocument) {
         [self removeResolution];
     }
-    return result;
+    return error;
 }
 
 -(BOOL)setResolutionString:(NSString *)resolution forSchema:(NSDictionary *)schema
@@ -264,7 +290,7 @@ -(void)removeResolution
     [self.schemaStack removeLastObject];
 }
 
--(BOOL)validateJSONInstance:(id)json withSchemaData:(NSData*)schemaData
+-(NSError*)validateJSONInstance:(id)json withSchemaData:(NSData*)schemaData
 {
     NSError * error = nil;
     NSString * jsonKey = nil;
@@ -275,17 +301,17 @@ -(BOOL)validateJSONInstance:(id)json withSchemaData:(NSData*)schemaData
         json = @{jsonKey : json};
         //        schema = @{@"properties" : @{@"debugInvalidTopTypeKey" : schema}};
 #else
-        return NO;
+        return ValidationError(@"", @"is not valid JSON Object");
 #endif
     }
     NSData * jsonData = [NSJSONSerialization dataWithJSONObject:json options:0 error:&error];
-    if (error != nil) {
-        return NO;
+    if (error) {
+        return error;
     }
     return [self validateJSONData:jsonData withKey:jsonKey withSchemaData:schemaData];
 }
 
--(BOOL)validateJSONInstance:(id)json withSchema:(NSDictionary*)schema;
+-(NSError*)validateJSONInstance:(id)json withSchema:(NSDictionary*)schema
 {
     NSError * error = nil;
     NSString * jsonKey = nil;
@@ -296,104 +322,103 @@ -(BOOL)validateJSONInstance:(id)json withSchema:(NSDictionary*)schema;
         json = @{jsonKey : json};
 //        schema = @{@"properties" : @{@"debugInvalidTopTypeKey" : schema}};
 #else
-        return NO;
+        return ValidationError(@"", @"is not valid JSON object");
 #endif
     }
     NSData * jsonData = [NSJSONSerialization dataWithJSONObject:json options:0 error:&error];
-    if (error != nil) {
-        return NO;
+    if (error ) {
+        return error;
     }
     NSData * schemaData = [NSJSONSerialization dataWithJSONObject:schema options:0 error:&error];
-    if (error != nil) {
-        return NO;
+    if (error) {
+        return error;
     }
     return [self validateJSONData:jsonData withKey:jsonKey withSchemaData:schemaData];
 }
 
--(BOOL)validateJSONData:(NSData*)jsonData withSchemaData:(NSData*)schemaData
+-(NSError*)validateJSONData:(NSData*)jsonData withSchemaData:(NSData*)schemaData
 {
     return [self validateJSONData:jsonData withKey:nil withSchemaData:schemaData];
 }
 
--(BOOL)validateJSONData:(NSData*)jsonData withKey:(NSString*)key withSchemaData:(NSData*)schemaData
+-(NSError*)validateJSONData:(NSData*)jsonData withKey:(NSString*)key withSchemaData:(NSData*)schemaData
 {
     NSError * error = nil;
     id json = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
-    if (error != nil) {
-        return NO;
+    if (error) {
+        return ValidationError(@"", @"JSON data MUST be valid JSON: @%", error.localizedDescription);
     }
     if (key != nil) {
         json = json[key];
     }
     id schema = [NSJSONSerialization JSONObjectWithData:schemaData options:0 error:&error];
-    if (error != nil) {
-        return NO;
+    if (error) {
+        return ValidationError(@"", @"Scheme MUST be valid JSON: %@", error.localizedDescription);
     }
     if (![schema isKindOfClass:[NSDictionary class]]) {
-        return NO;
-    }
-    if (![self validateJSON:json withSchemaDict:schema]) {
-        return NO;
+        return ValidationError(@"", @"Schema MUST be 'object' type. Not %@", [schema class]);
     }
-    return YES;
+    return [self validateJSON:json withSchemaDict:schema];
 }
 
--(BOOL)validateJSON:(id)json withSchemaDict:(NSDictionary *)schema
+-(NSError*)validateJSON:(id)json withSchemaDict:(NSDictionary *)schema
 {
     @synchronized(self)
     {
-        if (!schema ||
-            ![schema isKindOfClass:[NSDictionary class]]) {
+        if (!schema || ![schema isKindOfClass:[NSDictionary class]]) {
             //NSLog(@"No schema specified, or incorrect data type: %@", schema);
-            return NO;
+            return ValidationError(@"", @"Schema must be 'object' type. Not %@", [schema class]);
         }
-
         //need to make sure the validation of schema doesn't infinitely recurse (self references)
         // therefore should not expand any subschemas, and ensure schema are only checked on a 'top' level.
         //first validate the schema against the root schema then validate against the original
         //first check valid json (use NSJSONSerialization)
-
-        self.validationStack = [NSMutableArray new];
-        self.resolutionStack = [NSMutableArray new];
-        self.schemaStack = [NSMutableArray new];
-
+        
+        self.validationStack = [NSMutableArray array];
+        self.resolutionStack = [NSMutableArray array];
+        self.schemaStack = [NSMutableArray array];
+        
         [self setResolutionString:@"#" forSchema:schema];
         
-        if (![self _validateJSON:schema withSchemaDict:self.rootSchema]) {
-            return NO; //error: invalid schema
+        NSError* error = [self _validateJSON:schema withSchemaDict:self.rootSchema path:@""];
+        if (error) {
+            return ValidationError(@"", @"Invalid schema: %@", error.localizedDescription);
         }
-        if (![self _validateJSON:json withSchemaDict:schema]) {
-            return NO;
+        
+        error = [self _validateJSON:json withSchemaDict:schema path:@""];
+        if (error) {
+            return error;
         }
-
+        
         [self removeResolution];
-        return YES;
+        return nil;
     }
 }
 
--(BOOL)_validateJSON:(id)json withSchemaDict:(NSDictionary *)schema
+-(NSError*)_validateJSON:(id)json withSchemaDict:(NSDictionary *)schema path:( NSString* )path
 {
     NSParameterAssert(schema != nil);
     //check stack for JSON and schema
     //push to stack the json and the schema.
-    if (![self pushToStackJSON:json forSchema:schema]) {
-        return NO;
+    NSError* error = [self pushToStackJSON:json forSchema:schema];
+    if (error) {
+        return error;
     }
     BOOL newResolution = NO;
     NSString *resolutionValue = schema[@"id"];
     if (resolutionValue) {
         newResolution = [self setResolutionString:resolutionValue forSchema:schema];
     }
-    BOOL result = [self __validateJSON:json withSchemaDict:schema];
+    error = [self __validateJSON:json withSchemaDict:schema path:path];
     //pop from the stacks
     if (newResolution) {
         [self removeResolution];
     }
     [self popStack];
-    return result;
+    return error;
 }
 
--(BOOL)__validateJSON:(id)json withSchemaDict:(NSDictionary *)schema
+-(NSError*)__validateJSON:(id)json withSchemaDict:(NSDictionary *)schema path:( NSString* )path
 {
     //TODO: synonyms (potentially in higher level too)
     
@@ -424,42 +449,43 @@ -(BOOL)__validateJSON:(id)json withSchemaDict:(NSDictionary *)schema
     //        }
     //    }
 
-    if (schema[@"$ref"]) {
-        if (![schema[@"$ref"] isKindOfClass:[NSString class]]) {
-            return NO;
+    NSString* schemaRef = schema[@"$ref"];
+    if (schemaRef) {
+        if (![schemaRef isKindOfClass:[NSString class]]) {
+            return ValidationError(path, @"$ref '%@' is '%@' type, but MUST be a 'string' type", schemaRef, [schemaRef class]);
         }
-        return [self validateJSON:json withSchemaAtReference:schema[@"$ref"]];
+        return [self validateJSON:json withSchemaAtReference:schemaRef path:path];
     }
 
     NSString *type = nil;
-    SEL typeValidator = nil;
+    NSError*(^typeValidator)() = nil;
     if ([json isKindOfClass:[NSArray class]]) {
         type = @"array";
-        typeValidator = @selector(_validateJSONArray:withSchemaDict:);
+        typeValidator = ^{ return [self _validateJSONArray:json withSchemaDict:schema path:[path stringByAppendingPathComponent:@"Array"]]; };
     } else if ([json isKindOfClass:[NSNumber class]]) {
         NSParameterAssert(strcmp( [@YES objCType], @encode(char) ) == 0);
         if (strcmp( [json objCType], @encode(char) ) == 0) {
             type = @"boolean";
         } else {
-            typeValidator = @selector(_validateJSONNumeric:withSchemaDict:);
             double num = [json doubleValue];
             if ((num - floor(num)) == 0.0) {
                 type = @"integer";
             } else {
                 type = @"number";
             }
+            typeValidator = ^{ return [self _validateJSONNumeric:json withSchemaDict:schema path:[path stringByAppendingFormat:@"(%@)", type]]; };
         }
     } else if ([json isKindOfClass:[NSNull class]]) {
         type = @"null";
     } else if ([json isKindOfClass:[NSDictionary class]]) {
         type = @"object";
-        typeValidator = @selector(_validateJSONObject:withSchemaDict:);
+        typeValidator = ^{ return [self _validateJSONObject:json withSchemaDict:schema path:[path stringByAppendingPathComponent:@"Object"]]; };
         
     } else if ([json isKindOfClass:[NSString class]]) {
         type = @"string";
-        typeValidator = @selector(_validateJSONString:withSchemaDict:);
+        typeValidator = ^{ return [self _validateJSONString:json withSchemaDict:schema path:[path stringByAppendingString:@"(string)"]]; };
     } else {
-        return NO; // the schema is not one of the valid types.
+        return ValidationError(path, @"The schema '%@' is not one of the valid types", [json class]); // the schema is not one of the valid types.
     }    
     
     //TODO: extract the types first before the check (if there is no type specified, we'll never hit the checking code
@@ -470,7 +496,7 @@ -(BOOL)__validateJSON:(id)json withSchemaDict:(NSDictionary *)schema
             if ([keyword isEqualToString:@"enum"]) {
                 //An instance validates successfully against this keyword if its value is equal to one of the elements in this keyword's array value.
                 if (![schemaItem containsObject:json]) {
-                    return NO; 
+                    return ValidationError(path, @"enum '%@' does not contain '%@'", schemaItem, json);
                 }
             } else if ([keyword isEqualToString:@"type"]) {
                 if ([schemaItem isKindOfClass:[NSString class]]) {
@@ -478,37 +504,47 @@ -(BOOL)__validateJSON:(id)json withSchemaDict:(NSDictionary *)schema
                         continue; 
                     }
                     if (![schemaItem isEqualToString:type]) {
-                        return NO; 
+                        return ValidationError(path, @"MUST be type '%@' not '%@'", schemaItem, type);
                     }
                 } else { //array
                     if (![schemaItem containsObject:type]) {
-                        return NO; 
+                        return ValidationError(path,@"MUST be in '%@' not '%@'", schemaItem, type);
                     }
                 }
             } else if ([keyword isEqualToString:@"allOf"]) {
                 for (NSDictionary * subSchema in schemaItem) {
-                    if (![self _validateJSON:json withSchemaDict:subSchema]) { return NO; }
+                    NSError* error = [self _validateJSON:json withSchemaDict:subSchema path:path];
+                    if (error) {
+                        return error;
+                    }
                 }
             } else if ([keyword isEqualToString:@"anyOf"]) {
-                BOOL anySuccess = NO;
                 for (NSDictionary * subSchema in schemaItem) {
-                    if ([self _validateJSON:json withSchemaDict:subSchema]) {
-                        anySuccess = YES;
-                        break;
+                    NSError* error = [self _validateJSON:json withSchemaDict:subSchema path:path];
+                    if (error == nil) {
+                        return nil;
                     }
                 }
-                if (!anySuccess) {
-                    return NO;
-                }
+                return ValidationError(path, @"MUST be ANY OF '%@' not '%@'", schemaItem, json);
             } else if ([keyword isEqualToString:@"oneOf"]) {
                 int passes = 0;
                 for (NSDictionary * subSchema in schemaItem) {
-                    if ([self _validateJSON:json withSchemaDict:subSchema]) { passes++; }
-                    if (passes > 1) { return NO; }
+                    NSError* error = [self _validateJSON:json withSchemaDict:subSchema path:path];
+                    if (!error) {
+                        passes++;
+                    }
+                    if (passes > 1) {
+                        return ValidationError(path, @"MUST be ONE OF '%@' not '%@'", schemaItem, json);
+                    }
+                }
+                if (passes != 1) {
+                    return ValidationError(path, @"MUST be ONE OF '%@' not '%@'", schemaItem, json);
                 }
-                if (passes != 1) { return NO; }
             } else if ([keyword isEqualToString:@"not"]) {
-                if ([self _validateJSON:json withSchemaDict:schemaItem]) { return NO; }
+                NSError* error = [self _validateJSON:json withSchemaDict:schemaItem path:path];
+                if (error == nil) {
+                    return ValidationError(path, @"'%@' MUST be NOT '%@'", json, schemaItem);
+                }
             } else if ([keyword isEqualToString:@"definitions"]) {
                 
             }
@@ -516,18 +552,14 @@ -(BOOL)__validateJSON:(id)json withSchemaDict:(NSDictionary *)schema
     }
     
     if (typeValidator != nil) {
-        IMP imp = [self methodForSelector:typeValidator];
-        BOOL (*func)(id, SEL, id, id) = (BOOL(*)(id, SEL, id, id))imp;
-        if (!func(self, typeValidator, json, schema)) {
-            return NO;
-        }
+        return typeValidator();
     }
     
-    return YES;
+    return nil;
 }
 
 //for number and integer
--(BOOL)_validateJSONNumeric:(NSNumber*)jsonNumber withSchemaDict:(NSDictionary*)schema
+-(NSError*)_validateJSONNumeric:(NSNumber*)jsonNumber withSchemaDict:(NSDictionary*)schema path:( NSString* )path
 {
     static NSArray * numericKeywords;
     static dispatch_once_t onceToken;
@@ -535,8 +567,11 @@ -(BOOL)_validateJSONNumeric:(NSNumber*)jsonNumber withSchemaDict:(NSDictionary*)
         numericKeywords = @[@"multipleOf", @"maximum",/* @"exclusiveMaximum",*/ @"minimum",/* @"exclusiveMinimum"*/];
     });
     
-    if (!schema || ![schema isKindOfClass:[NSDictionary class]]) {
-        return NO;
+    if (!schema) {
+        return ValidationError(path, @"no schema for '%@'", jsonNumber);
+    }
+    if (![schema isKindOfClass:[NSDictionary class]]) {
+        return ValidationError(path, @"schema is not is object '%@'", schema);
     }
     
     for (NSString * keyword in numericKeywords) {
@@ -547,39 +582,39 @@ -(BOOL)_validateJSONNumeric:(NSNumber*)jsonNumber withSchemaDict:(NSDictionary*)
                 //A numeric instance is valid against "multipleOf" if the result of the division of the instance by this keyword's value is an integer.
                 double divResult = [jsonNumber doubleValue] / [schemaItem doubleValue];
                 if ((divResult - floor(divResult)) != 0.0) {
-                    return NO;
+                    return ValidationError(path, @"multipleOf");
                 }
             } else if ([keyword isEqualToString:@"maximum"]) {
                 if ([schema[@"exclusiveMaximum"] isKindOfClass:[NSNumber class]] && [schema[@"exclusiveMaximum"] boolValue] == YES) {
                     if (!([jsonNumber doubleValue] < [schemaItem doubleValue])) {
                         //if "exclusiveMaximum" has boolean value true, the instance is valid if it is strictly lower than the value of "maximum".
-                        return NO;
+                        return ValidationError(path, @"'%@' MUST be lower than '%@'", jsonNumber, schemaItem);
                     }
                 } else {
                     if (!([jsonNumber doubleValue] <= [schemaItem doubleValue])) {
                         //if "exclusiveMaximum" is not present, or has boolean value false, then the instance is valid if it is lower than, or equal to, the value of "maximum"
-                        return NO;
+                        return ValidationError(path, @"'%@' MUST be lower than, or equal to '%@'", jsonNumber, schemaItem);
                     }
                 }
             } else if ([keyword isEqualToString:@"minimum"]) {
                 if ([schema[@"exclusiveMinimum"] isKindOfClass:[NSNumber class]] && [schema[@"exclusiveMinimum"] boolValue] == YES) {
                     if (!([jsonNumber doubleValue] > [schemaItem doubleValue])) {
                         //if "exclusiveMinimum" is present and has boolean value true, the instance is valid if it is strictly greater than the value of "minimum".
-                        return NO;
+                        return ValidationError(path, @"'%@' MUST be greater than '%@'", jsonNumber, schemaItem);
                     }
                 } else {
                     if (!([jsonNumber doubleValue] >= [schemaItem doubleValue])) {
                         //if "exclusiveMinimum" is not present, or has boolean value false, then the instance is valid if it is greater than, or equal to, the value of "minimum"
-                        return NO;
+                        return ValidationError(path, @"'%@' MUST be greater than, or equal to '%@'", jsonNumber, schemaItem);
                     }
                 }
             }
         }
     }
-    return YES;
+    return nil;
 }
 
--(BOOL)_validateJSONString:(NSString*)jsonString withSchemaDict:(NSDictionary*)schema
+-(NSError*)_validateJSONString:(NSString*)jsonString withSchemaDict:(NSDictionary*)schema path:( NSString* )path
 {
     static NSArray * stringKeywords;
     static dispatch_once_t onceToken;
@@ -599,12 +634,16 @@ -(BOOL)_validateJSONString:(NSString*)jsonString withSchemaDict:(NSDictionary*)s
                 // Go read this if you care: http://www.objc.io/issue-9/unicode.html (See Common Pitfalls - Length)
                 NSInteger realLength = [jsonString lengthOfBytesUsingEncoding:NSUTF32StringEncoding] / 4;
                 
-                if (!(realLength <= [schemaItem integerValue])) { return NO; }
+                if (!(realLength <= [schemaItem integerValue])) {
+                    return ValidationError(path, @"string '%@' length MUST be less than, or equal to %d", jsonString, realLength);
+                }
             } else if ([keyword isEqualToString:@"minLength"]) {
                 //A string instance is valid against this keyword if its length is greater than, or equal to, the value of this keyword.
                 
                 NSInteger realLength = [jsonString lengthOfBytesUsingEncoding:NSUTF32StringEncoding] / 4;
-                if (!(realLength >= [schemaItem intValue])) { return NO; }
+                if (!(realLength >= [schemaItem intValue])) {
+                    return ValidationError(path, @"string '%@' length MUST be greater than, or equal to %d", jsonString, realLength);
+                }
             } else if ([keyword isEqualToString:@"pattern"]) {
                 //A string instance is considered valid if the regular expression matches the instance successfully. Recall: regular expressions are not implicitly anchored.
                 //This string SHOULD be a valid regular expression, according to the ECMA 262 regular expression dialect.
@@ -616,15 +655,15 @@ -(BOOL)_validateJSONString:(NSString*)jsonString withSchemaDict:(NSDictionary*)s
                 }
                 if (NSEqualRanges([regex rangeOfFirstMatchInString:jsonString options:0 range:NSMakeRange(0, jsonString.length)], NSMakeRange(NSNotFound, 0))) {
                     //A string instance is considered valid if the regular expression matches the instance successfully. Recall: regular expressions are not implicitly anchored.
-                    return NO;
+                    return ValidationError(path, @"string does not match regular expression: %@", schemaItem);
                 }
             }
         }
     }
-    return YES;
+    return nil;
 }
 
--(BOOL)_validateJSONObject:(NSDictionary*)jsonDict withSchemaDict:(NSDictionary*)schema
+-(NSError*)_validateJSONObject:(NSDictionary*)jsonDict withSchemaDict:(NSDictionary*)schema path:( NSString* )path
 {
     static NSArray * objectKeywords;
     static dispatch_once_t onceToken;
@@ -638,26 +677,37 @@ -(BOOL)_validateJSONObject:(NSDictionary*)jsonDict withSchemaDict:(NSDictionary*
 
             if ([keyword isEqualToString:@"maxProperties"]) {
                 //An object instance is valid against "maxProperties" if its number of properties is less than, or equal to, the value of this keyword.
-                if ((NSInteger)[jsonDict count] > [schemaItem integerValue]) { return NO; /*invalid JSON dict*/ }
+                if ((NSInteger)[jsonDict count] > [schemaItem integerValue]) {
+                    return ValidationError(path, @"properties count (%d) MUST be less than, or equal to %@", jsonDict.count, schemaItem); /*invalid JSON dict*/
+                }
             } else if ([keyword isEqualToString:@"minProperties"]) {
                 //An object instance is valid against "minProperties" if its number of properties is greater than, or equal to, the value of this keyword.
-                if ((NSInteger)[jsonDict count] < [schemaItem integerValue]) { return NO; /*invalid JSON dict*/ }
+                if ((NSInteger)[jsonDict count] < [schemaItem integerValue]) {
+                    return ValidationError(path, @"properties count (%d) MUST be greater than, or equal to %@", jsonDict.count, schemaItem); /*invalid JSON dict*/
+                }
             } else if ([keyword isEqualToString:@"required"]) {
                 NSArray * requiredArray = schemaItem;
                 for (NSObject * requiredProp in requiredArray) {
                     NSString * requiredPropStr = (NSString*)requiredProp;
                     if (![jsonDict valueForKey:requiredPropStr]) {
-                        return NO; //required not present. invalid JSON dict.
+                        return ValidationError(path, @"required property '%@' is not present", requiredPropStr); //required not present. invalid JSON dict.
                     }
                 }
-            } else if (!doneProperties && ([keyword isEqualToString:@"properties"] || [keyword isEqualToString:@"patternProperties"] || [keyword isEqualToString:@"additionalProperties"])) {
+            } else if (!doneProperties && ([keyword isEqualToString:@"properties"] ||
+                                           [keyword isEqualToString:@"patternProperties"] ||
+                                           [keyword isEqualToString:@"additionalProperties"])) {
                 doneProperties = YES;
                 NSDictionary * properties = schema[@"properties"];
                 NSDictionary * patternProperties = schema[@"patternProperties"];
                 id additionalProperties = schema[@"additionalProperties"];
-                if (properties == nil) { properties = [NSDictionary new]; }
-                if (patternProperties == nil) { patternProperties = [NSDictionary new]; }
-                if (additionalProperties == nil || ([additionalProperties isKindOfClass:[NSNumber class]] && strcmp([additionalProperties objCType], @encode(char)) == 0 && [additionalProperties boolValue] == YES)) {
+                if (properties == nil) {
+                    properties = [NSDictionary new];
+                }
+                
+                if (patternProperties == nil) {
+                    patternProperties = [NSDictionary new];
+                }
+                if (!additionalProperties || ([additionalProperties isKindOfClass:[NSNumber class]] && strcmp([additionalProperties objCType], @encode(char)) == 0 && [additionalProperties boolValue] == YES)) {
                     additionalProperties = [NSDictionary new];
                 }
                 
@@ -704,7 +754,7 @@ -(BOOL)_validateJSONObject:(NSDictionary*)jsonDict withSchemaDict:(NSDictionary*
                     //Because we have built a set of schemas/keys up (rather than down), the following test is equivalent to the requirement:
                     //Validation of the instance succeeds if, after these two steps, set "s" is empty.
                     if (testSchemas.count < allKeys.count) {
-                        return NO;
+                        return ValidationError(path, @"additionalProperties = NO");
                     }
                 } else {
                     //find keys from allkeys that are not in testSchemas and add additionalProperties
@@ -717,7 +767,9 @@ -(BOOL)_validateJSONObject:(NSDictionary*)jsonDict withSchemaDict:(NSDictionary*
                         additionalPropsSchema = additionalProperties;
                     }
                     NSMutableSet * additionalKeys = [allKeys mutableCopy];
-                    [additionalKeys minusSet:[testSchemas keysOfEntriesPassingTest:^BOOL(id key, id obj, BOOL *stop) { return YES; }]];
+                    [additionalKeys minusSet:[testSchemas keysOfEntriesPassingTest:^BOOL(id key, id obj, BOOL *stop) {
+                        return YES;
+                    }]];
                     for (NSString * key in additionalKeys) {
                         testSchemas[key] = [NSMutableArray arrayWithObject:additionalPropsSchema];
                     }
@@ -727,13 +779,18 @@ -(BOOL)_validateJSONObject:(NSDictionary*)jsonDict withSchemaDict:(NSDictionary*
                 for (NSString * property in [testSchemas keyEnumerator]) {
                     NSArray * subschemas = testSchemas[property];
                     for (NSDictionary * subschema in subschemas) {
-                        if (![self _validateJSON:jsonDict[property] withSchemaDict:subschema]) {
-                            return NO;
+                        NSError* error = [self _validateJSON:jsonDict[property]
+                                              withSchemaDict:subschema
+                                                        path:[path stringByAppendingFormat:@".%@", property]];
+                        if (error) {
+                            return error;
                         }
                     }
                 }
             } else if ([keyword isEqualToString:@"dependencies"]) {
-                NSSet * properties = [jsonDict keysOfEntriesPassingTest:^BOOL(id key, id obj, BOOL *stop) { return YES; }];
+                NSSet * properties = [jsonDict keysOfEntriesPassingTest:^BOOL(id key, id obj, BOOL *stop) {
+                    return YES;
+                }];
                 NSDictionary * dependencies = schemaItem;
                 for (NSString * name in [dependencies allKeys]) {
                     if (![properties containsObject:name]) {
@@ -745,25 +802,26 @@ -(BOOL)_validateJSONObject:(NSDictionary*)jsonDict withSchemaDict:(NSDictionary*
                         NSDictionary * schemaDependency = dependency;
                         //For all (name, schema) pair of schema dependencies, if the instance has a property by this name, then it must also validate successfully against the schema.
                         //Note that this is the instance itself which must validate successfully, not the value associated with the property name.
-                        if (![self _validateJSON:jsonDict withSchemaDict:schemaDependency]) {
-                            return NO;
+                        NSError* error = [self _validateJSON:jsonDict withSchemaDict:schemaDependency path:path];
+                        if (error) {
+                            return error;
                         }
                     } else if ([dependency isKindOfClass:[NSArray class]]) {
                         NSArray * propertyDependency = dependency;
                         //For each (name, propertyset) pair of property dependencies, if the instance has a property by this name, then it must also have properties with the same names as propertyset.
                         NSSet * propertySet = [NSSet setWithArray:propertyDependency];
                         if (![propertySet isSubsetOfSet:properties]) {
-                            return NO;
+                            return ValidationError(path, @"For each (name, propertyset) pair of property dependencies, if the instance has a property by this name, then it must also have properties with the same names as propertyset");
                         }
                     }
                 }
             }
         }
     }
-    return YES;
+    return nil;
 }
 
--(BOOL)_validateJSONArray:(NSArray*)jsonArray withSchemaDict:(NSDictionary*)schema
+-(NSError*)_validateJSONArray:(NSArray*)jsonArray withSchemaDict:(NSDictionary*)schema path:( NSString* )path
 {
     static NSArray * arrayKeywords;
     static dispatch_once_t onceToken;
@@ -780,42 +838,51 @@ -(BOOL)_validateJSONArray:(NSArray*)jsonArray withSchemaDict:(NSDictionary*)sche
                 doneItems = YES;
                 id additionalItems = schema[@"additionalItems"];
                 id items = schema[@"items"];
-                if (additionalItems == nil) { additionalItems = [NSDictionary new];}
-                if (items == nil) { items = [NSDictionary new];}
+                if (additionalItems == nil) {
+                    additionalItems = [NSDictionary dictionary];
+                }
+                if (items == nil) {
+                    items = [NSDictionary dictionary];
+                }
                 if ([additionalItems isKindOfClass:[NSNumber class]] && strcmp([additionalItems objCType], @encode(char)) == 0 && [additionalItems boolValue] == YES) {
-                    additionalItems = [NSDictionary new];
+                    additionalItems = [NSDictionary dictionary];
                 }
                 
                 for (NSUInteger index = 0; index < [jsonArray count]; index++) {
                     id child = jsonArray[index];
                     if ([items isKindOfClass:[NSDictionary class]]) {
                         //If items is a schema, then the child instance must be valid against this schema, regardless of its index, and regardless of the value of "additionalItems".
-                        if (![self _validateJSON:jsonArray[index] withSchemaDict:items]) {
-                            return NO;
+                        NSError* error = [self _validateJSON:jsonArray[index] withSchemaDict:items path:[path stringByAppendingPathComponent:@"Object"]];
+                        if (error) {
+                            return error;
                         }
                     } else if ([items isKindOfClass:[NSArray class]]) {
                         if (index < [(NSArray *)items count]) {
-                            if (![self _validateJSON:child withSchemaDict:items[index]]) {
-                                return NO;
+                            NSError* error = [self _validateJSON:child withSchemaDict:items[index] path:[path stringByAppendingPathComponent:@"Array"]];
+                            if (error) {
+                                return error;
                             }
                         } else {
                             if ([additionalItems isKindOfClass:[NSNumber class]] && [additionalItems boolValue] == NO) {
                                 //if the value of "additionalItems" is boolean value false and the value of "items" is an array, the instance is valid if its size is less than, or equal to, the size of "items".
-                                return NO;
+                                return ValidationError(path, @"If the value of 'additionalItems' == false and the value of 'items' is an array, the instance is valid if its size is less than, or equal to, the size of 'items'");
                             } else {
-                                if (![self _validateJSON:child withSchemaDict:additionalItems]) {
-                                    return NO;
+                                NSError* error = [self _validateJSON:child withSchemaDict:additionalItems path:path];
+                                if (error) {
+                                    return error;
                                 }
                             }
                         }
                     }
                 }
             } else if ([keyword isEqualToString:@"maxItems"]) {
-                //An array instance is valid against "maxItems" if its size is less than, or equal to, the value of this keyword.
-                if ((NSInteger)[jsonArray count] > [schemaItem integerValue]) { return NO; }
-                //An array instance is valid against "minItems" if its size is greater than, or equal to, the value of this keyword.
+                if ((NSInteger)[jsonArray count] > [schemaItem integerValue]){
+                    return ValidationError(path, @"An array instance is valid against 'maxItems' if its size is less than, or equal to, the value of this keyword.");
+                }
             } else if ([keyword isEqualToString:@"minItems"]) {
-                if ((NSInteger)[jsonArray count] < [schemaItem integerValue]) { return NO; }
+                if ((NSInteger)[jsonArray count] < [schemaItem integerValue]) {
+                    return ValidationError(path, @"An array instance is valid against 'minItems' if its size is greater than, or equal to, the value of this keyword.");
+                }
             } else if ([keyword isEqualToString:@"uniqueItems"]) {
                 if ([schemaItem isKindOfClass:[NSNumber class]] && [schemaItem boolValue] == YES) {
                     //If it has boolean value true, the instance validates successfully if all of its elements are unique.
@@ -835,13 +902,13 @@ -(BOOL)_validateJSONArray:(NSArray*)jsonArray withSchemaDict:(NSDictionary*)sche
 
                     if (([uniqueItems count] + fudgeFactor) < [jsonArray count])
                     {
-                        return NO;
+                        return ValidationError(path, @"All elements MUST be unique");
                     }
                 }
             }
         }
     }
-    return YES;
+    return nil;
 }
 
 - (BOOL)valuesHaveOneAndTrue:(NSArray *)values
@@ -910,4 +977,8 @@ -(BOOL)checkSchemaRef:(NSDictionary*)schema
     }
 }
 
+-(NSString *)description{
+    return [NSString stringWithFormat:@"<%@ %p\n%@>", NSStringFromClass(self.class), self, self.schemaRefs];
+}
+
 @end
diff --git a/Tests/KiteJSONValidatorTests.m b/Tests/KiteJSONValidatorTests.m
index 2ce4ff5..0e42445 100644
--- a/Tests/KiteJSONValidatorTests.m
+++ b/Tests/KiteJSONValidatorTests.m
@@ -15,18 +15,6 @@ @interface Tests : XCTestCase
 
 @implementation Tests
 
-- (void)setUp
-{
-    [super setUp];
-    // Put setup code here. This method is called before the invocation of each test method in the class.
-}
-
-- (void)tearDown
-{
-    // Put teardown code here. This method is called after the invocation of each test method in the class.
-    [super tearDown];
-}
-
 - (void)testDraft4Suite
 {
     NSBundle * mainBundle = [NSBundle bundleForClass:[self class]];
@@ -56,13 +44,19 @@ - (void)testDraft4Suite
                     NSData * data = [NSData dataWithContentsOfFile:fullpath];
                     NSURL * url = [NSURL URLWithString:@"http://localhost:1234/"];
                     url = [NSURL URLWithString:refPath relativeToURL:url];
-                    BOOL success = [validator addRefSchemaData:data atURL:url];
-                    XCTAssertTrue(success == YES, @"Unable to add the reference schema at '%@'", url);
+                    NSError* addRefError = [validator addRefSchemaData:data atURL:url];
+                    XCTAssertNil(addRefError, @"Unable to add the reference schema at '%@': %@", url, addRefError.localizedDescription);
                 }
                 
-                BOOL result = [validator validateJSONInstance:json[@"data"] withSchema:test[@"schema"]];
+                error = [validator validateJSONInstance:json[@"data"] withSchema:test[@"schema"]];
                 BOOL desired = [json[@"valid"] boolValue];
-                if (result != desired) {
+                
+                if (error)
+                {
+                    NSLog(@"error: %@", error.localizedDescription);
+                }
+                
+                if ((error?YES:NO) == desired) {
                     XCTFail(@"Category: %@ Test: %@ Expected result: %i", test[@"description"], json[@"description"], desired);
                 }
                 else