FluentValidation/FluentValidation · error · ValidationTestException
Expected validation error was not found
Error message
Expected validation error was not found
What it means
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.
Source
Thrown at src/FluentValidation/TestHelper/ValidatorTestExtensions.cs:149
if (failure.FormattedMessagePlaceholderValues.ContainsKey(messageArgumentMatches[i].Groups[1].Value)) {
formattedExceptionMessage = formattedExceptionMessage.Replace(messageArgumentMatches[i].Value, failure.FormattedMessagePlaceholderValues[messageArgumentMatches[i].Groups[1].Value].ToString());
}
}
return formattedExceptionMessage;
}
return defaultMessage;
}
public static ITestValidationWith When(this ITestValidationContinuation failures, Func<ValidationFailure, bool> failurePredicate, string exceptionMessage = null) {
var result = new TestValidationContinuation(failures.MatchedFailures, failures);
result.ApplyPredicate(failurePredicate);
var anyMatched = result.Any();
if (!anyMatched) {
var failure = result.UnmatchedFailures.FirstOrDefault();
string message = BuildErrorMessage(failure, exceptionMessage, "Expected validation error was not found");
throw new ValidationTestException(message);
}
return result;
}
public static ITestValidationContinuation WhenAll(this ITestValidationContinuation failures, Func<ValidationFailure, bool> failurePredicate, string exceptionMessage = null) {
var result = new TestValidationContinuation(failures.MatchedFailures, failures);
result.ApplyPredicate(failurePredicate);
bool allMatched = !result.UnmatchedFailures.Any();
if (!allMatched) {
var failure = result.UnmatchedFailures.First();
string message = BuildErrorMessage(failure, exceptionMessage, "Found an unexpected validation error");
throw new ValidationTestException(message);
}
return result;
View on GitHub (pinned to daa00b7954)
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.
Example fix
// before
result.ShouldHaveValidationErrorFor(x => x.Age)
.When(f => f.ErrorMessage == "Must be over 18 yrs");
// after (match the validator's actual message)
result.ShouldHaveValidationErrorFor(x => x.Age)
.When(f => f.ErrorMessage == "Age must be greater than 18"); Defensive patterns
Strategy: validation
Validate before calling
// Inspect actual failures before asserting, so a mismatch is debuggable.
var result = await validator.TestValidateAsync(model);
var produced = result.Errors
.Select(f => $"{f.PropertyName}={f.ErrorMessage} ({f.Severity})")
.ToList();
// Only call .When(...) once you know a matching failure exists.
if (!produced.Any(m => m.Contains("Age"))) {
Assert.Fail("Validator produced no Age failure. Saw: " + string.Join("; ", produced));
}
result.ShouldHaveValidationErrorFor(x => x.Age) Try / catch
// Catch only in framework-level helpers, not in normal test bodies.
try { result.ShouldHaveValidationErrorFor(x => x.Age).When(pred); }
catch (ValidationTestException ex) {
Assert.Fail($"Assertion failed: {ex.Message}. Errors: {string.Join(", ", result.Errors.Select(e => e.ErrorMessage))}");
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Found an unexpected validation error
- Expected to have errors only matching specified conditions
- Expected at least one validation error, but none were found.
- Expected a validation error for property {propertyName}
- Expected no validation errors for property {propertyName}
AI-assisted analysis of FluentValidation/FluentValidation@daa00b7954 (2026-08-13).
Data as JSON: /api/errors/19bcb419ab5b554d.
Report an issue: GitHub.