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

  1. Inspect TestValidationResult.Errors to confirm the validator actually produced failures and check the exact PropertyName/ErrorMessage/Severity values.
  2. Correct the predicate to match the real failure (fix typos, expected message text, or severity enum value).
  3. 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

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


AI-assisted analysis of FluentValidation/FluentValidation@daa00b7954 (2026-08-13). Data as JSON: /api/errors/19bcb419ab5b554d. Report an issue: GitHub.