{"record":{"id":"19bcb419ab5b554d","repo":"FluentValidation/FluentValidation","slug":"expected-validation-error-was-not-found","errorCode":null,"errorMessage":"Expected validation error was not found","messagePattern":"Expected validation error was not found","errorType":"exception","errorClass":"ValidationTestException","httpStatus":null,"severity":"error","filePath":"src/FluentValidation/TestHelper/ValidatorTestExtensions.cs","lineNumber":149,"sourceCode":"\t\t\t\tif (failure.FormattedMessagePlaceholderValues.ContainsKey(messageArgumentMatches[i].Groups[1].Value)) {\r\n\t\t\t\t\tformattedExceptionMessage = formattedExceptionMessage.Replace(messageArgumentMatches[i].Value, failure.FormattedMessagePlaceholderValues[messageArgumentMatches[i].Groups[1].Value].ToString());\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn formattedExceptionMessage;\r\n\t\t}\r\n\t\treturn defaultMessage;\r\n\t}\r\n\r\n\r\n\tpublic static ITestValidationWith When(this ITestValidationContinuation failures, Func<ValidationFailure, bool> failurePredicate, string exceptionMessage = null) {\r\n\t\tvar result = new TestValidationContinuation(failures.MatchedFailures, failures);\r\n\t\tresult.ApplyPredicate(failurePredicate);\r\n\r\n\t\tvar anyMatched = result.Any();\r\n\t\tif (!anyMatched) {\r\n\t\t\tvar failure = result.UnmatchedFailures.FirstOrDefault();\r\n\t\t\tstring message = BuildErrorMessage(failure, exceptionMessage, \"Expected validation error was not found\");\r\n\t\t\tthrow new ValidationTestException(message);\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic static ITestValidationContinuation WhenAll(this ITestValidationContinuation failures, Func<ValidationFailure, bool> failurePredicate, string exceptionMessage = null) {\r\n\t\tvar result = new TestValidationContinuation(failures.MatchedFailures, failures);\r\n\t\tresult.ApplyPredicate(failurePredicate);\r\n\r\n\t\tbool allMatched = !result.UnmatchedFailures.Any();\r\n\r\n\t\tif (!allMatched) {\r\n\t\t\tvar failure = result.UnmatchedFailures.First();\r\n\t\t\tstring message = BuildErrorMessage(failure, exceptionMessage, \"Found an unexpected validation error\");\r\n\t\t\tthrow new ValidationTestException(message);\r\n\t\t}\r\n\r\n\t\treturn result;\r","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/FluentValidation/FluentValidation/blob/daa00b795450881c233253488e3ddeb362f59f56/src/FluentValidation/TestHelper/ValidatorTestExtensions.cs#L131-L167","documentation":"Thrown by the When assertion helper on a TestValidationResult when none of the current failures satisfy the supplied predicate. It is the test-time counterpart of 'I expected at least one failure matching X, but found zero'. The message is built from the first unmatched failure (or null) to help you see what actually happened.","triggerScenarios":"Calling testValidationResult.Failures.When(f => ...) or ShouldHaveValidationErrorFor(...).When(predicate) where result.MatchedFailures is empty after applying the predicate. Common when chaining .When(...) on a continuation whose underlying failures all fail the predicate.","commonSituations":"You assert a specific ErrorMessage/PropertyName/Severity that the validator never produced. The validator passed (no failures at all) so nothing matches. Property name typo, wrong ruleset selected in TestValidate, or the rule was guarded by a When(condition) that was false for your test data.","solutions":["Inspect TestValidationResult.Errors to confirm the validator actually produced failures and check the exact PropertyName/ErrorMessage/Severity values.","Correct the predicate to match the real failure (fix typos, expected message text, or severity enum value).","If no failures were produced, feed input that actually trips the rule, or verify the rule's own When/Unless guard and ruleset selection."],"exampleFix":"// before\nresult.ShouldHaveValidationErrorFor(x => x.Age)\n     .When(f => f.ErrorMessage == \"Must be over 18 yrs\");\n\n// after (match the validator's actual message)\nresult.ShouldHaveValidationErrorFor(x => x.Age)\n     .When(f => f.ErrorMessage == \"Age must be greater than 18\");","handlingStrategy":"validation","validationCode":"// Inspect actual failures before asserting, so a mismatch is debuggable.\nvar result = await validator.TestValidateAsync(model);\nvar produced = result.Errors\n    .Select(f => $\"{f.PropertyName}={f.ErrorMessage} ({f.Severity})\")\n    .ToList();\n// Only call .When(...) once you know a matching failure exists.\nif (!produced.Any(m => m.Contains(\"Age\"))) {\n    Assert.Fail(\"Validator produced no Age failure. Saw: \" + string.Join(\"; \", produced));\n}\nresult.ShouldHaveValidationErrorFor(x => x.Age)","typeGuard":null,"tryCatchPattern":"// Catch only in framework-level helpers, not in normal test bodies.\ntry { result.ShouldHaveValidationErrorFor(x => x.Age).When(pred); }\ncatch (ValidationTestException ex) {\n    Assert.Fail($\"Assertion failed: {ex.Message}. Errors: {string.Join(\", \", result.Errors.Select(e => e.ErrorMessage))}\");\n}","preventionTips":["Print result.Errors when an assertion fails so you can see the real PropertyName/ErrorMessage.","Prefer the built-in ShouldHaveValidationErrorFor(x => x.Prop) over manual When predicates where possible.","Keep expected error messages in constants shared with the validator to avoid drift."],"tags":["testing","assertions","fluentvalidation"],"backgroundTag":null,"analyzedSha":"daa00b795450881c233253488e3ddeb362f59f56","analyzedAt":"2026-08-13T20:45:43.800Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}