slight improvements to error messaging

This commit is contained in:
2025-06-06 14:25:13 -04:00
parent d8a9a7b76b
commit fb333c6cbb
2 changed files with 14 additions and 18 deletions

View File

@ -146,7 +146,7 @@ fn format_drop_errors(raw_errors: Vec<(String, String, String)>, instance: &Valu
// 2. Deduplicate by instance_path and format as DropError
let mut unique_errors: HashMap<String, Value> = HashMap::new();
for (instance_path, schema_path, message) in plausible_errors {
for (instance_path, _schema_path, message) in plausible_errors {
if let Entry::Vacant(entry) = unique_errors.entry(instance_path.clone()) {
// Convert message to error code and make it human readable
let (code, human_message) = enhance_error_message(&message);
@ -158,11 +158,8 @@ fn format_drop_errors(raw_errors: Vec<(String, String, String)>, instance: &Valu
"code": code,
"message": human_message,
"details": {
"path": schema_path,
"context": json!({
"instance_path": instance_path,
"failing_value": failing_value
}),
"path": instance_path,
"context": failing_value,
"cause": message // Original error message
}
}));

View File

@ -153,16 +153,15 @@ fn test_cache_and_validate_json_schema() {
let invalid_result_type = validate_json_schema(schema_id, jsonb(invalid_instance_type));
assert_failure_with_json!(invalid_result_type, 1, "Value is below the minimum allowed", "Validation with invalid type should fail.");
let errors_type = invalid_result_type.0["errors"].as_array().unwrap();
assert_eq!(errors_type[0]["details"]["context"]["instance_path"], "/age");
assert_eq!(errors_type[0]["details"]["path"], "urn:my_schema#/properties/age");
assert_eq!(errors_type[0]["details"]["path"], "/age");
assert_eq!(errors_type[0]["details"]["context"], -5);
assert_eq!(errors_type[0]["code"], "MINIMUM_VIOLATED");
// Missing field
let invalid_result_missing = validate_json_schema(schema_id, jsonb(invalid_instance_missing));
assert_failure_with_json!(invalid_result_missing, 1, "Required field is missing", "Validation with missing field should fail.");
let errors_missing = invalid_result_missing.0["errors"].as_array().unwrap();
assert_eq!(errors_missing[0]["details"]["context"]["instance_path"], "");
assert_eq!(errors_missing[0]["details"]["path"], "urn:my_schema#");
assert_eq!(errors_missing[0]["details"]["path"], "");
assert_eq!(errors_missing[0]["code"], "REQUIRED_FIELD_MISSING");
// Schema not found
@ -208,9 +207,9 @@ fn test_cache_invalid_json_schema() {
// Both errors should have ENUM_VIOLATED code
assert_eq!(errors_array[0]["code"], "ENUM_VIOLATED");
assert_eq!(errors_array[1]["code"], "ENUM_VIOLATED");
// Check instance paths are preserved in context
// Check instance paths are preserved in path field
let paths: Vec<&str> = errors_array.iter()
.map(|e| e["details"]["context"]["instance_path"].as_str().unwrap())
.map(|e| e["details"]["path"].as_str().unwrap())
.collect();
assert!(paths.contains(&"/type"));
assert!(paths.contains(&"/type/0"));
@ -283,11 +282,11 @@ fn test_validate_json_schema_oneof_validation_errors() {
// Explicitly check that both expected errors are present, ignoring order
let errors_string = result_invalid_string.0["errors"].as_array().expect("Expected error array for invalid string");
assert!(errors_string.iter().any(|e|
e["details"]["context"]["instance_path"] == "/string_prop" &&
e["details"]["path"] == "/string_prop" &&
e["code"] == "MAX_LENGTH_VIOLATED"
), "Missing maxLength error");
assert!(errors_string.iter().any(|e|
e["details"]["context"]["instance_path"] == "" &&
e["details"]["path"] == "" &&
e["code"] == "REQUIRED_FIELD_MISSING"
), "Missing number_prop required error");
@ -299,11 +298,11 @@ fn test_validate_json_schema_oneof_validation_errors() {
// Explicitly check that both expected errors are present, ignoring order
let errors_number = result_invalid_number.0["errors"].as_array().expect("Expected error array for invalid number");
assert!(errors_number.iter().any(|e|
e["details"]["context"]["instance_path"] == "/number_prop" &&
e["details"]["path"] == "/number_prop" &&
e["code"] == "MINIMUM_VIOLATED"
), "Missing minimum error");
assert!(errors_number.iter().any(|e|
e["details"]["context"]["instance_path"] == "" &&
e["details"]["path"] == "" &&
e["code"] == "REQUIRED_FIELD_MISSING"
), "Missing string_prop required error");
@ -317,7 +316,7 @@ fn test_validate_json_schema_oneof_validation_errors() {
let errors_bool = result_invalid_bool.0["errors"].as_array().expect("Expected error array for invalid bool");
assert_eq!(errors_bool.len(), 1, "Expected exactly one error after deduplication");
assert_eq!(errors_bool[0]["code"], "TYPE_MISMATCH");
assert_eq!(errors_bool[0]["details"]["context"]["instance_path"], "");
assert_eq!(errors_bool[0]["details"]["path"], "");
// --- Test case 4: Fails missing required for both branches ---
// Input: empty object, expected string_prop (branch 0) OR number_prop (branch 1)
@ -329,7 +328,7 @@ fn test_validate_json_schema_oneof_validation_errors() {
let errors_empty = result_empty_obj.0["errors"].as_array().expect("Expected error array for empty object");
assert_eq!(errors_empty.len(), 1, "Expected exactly one error after filtering empty object");
assert_eq!(errors_empty[0]["code"], "REQUIRED_FIELD_MISSING");
assert_eq!(errors_empty[0]["details"]["context"]["instance_path"], "");
assert_eq!(errors_empty[0]["details"]["path"], "");
// The human message should be generic
assert_eq!(errors_empty[0]["message"], "Required field is missing");
}