LuckyPennySoftware/AutoMapper · error · InvalidOperationException
Type '{conditionType.Name}' does not implement IPreCondition
Error message
Type '{conditionType.Name}' does not implement IPreCondition<TSource, TDestination> What it means
Thrown by PreCondition<TCondition>() when the generic type argument does not implement the IPreCondition<TSource, TDestination> interface. The CreatePreConditionExpression method calls GetGenericInterface(typeof(IPreCondition<,>)) and throws InvalidOperationException if null. This is analogous to the Condition<ICondition<,,>> check but for the simpler two-type-argument pre-condition interface.
Source
Thrown at src/AutoMapper/Configuration/MemberConfigurationExpression.cs:134
ConditionCore((src, dest, srcMember, destMember, ctxt) => condition(src, dest, srcMember));
public void Condition(Func<TSource, TDestination, bool> condition) => ConditionCore((src, dest, srcMember, destMember, ctxt) => condition(src, dest));
public void Condition(Func<TSource, bool> condition) => ConditionCore((src, dest, srcMember, destMember, ctxt) => condition(src));
protected void ConditionCore(Expression<Func<TSource, TDestination, TMember, TMember, ResolutionContext, bool>> expr) =>
PropertyMapActions.Add(pm => pm.Condition = expr);
public void PreCondition<TCondition>() where TCondition : IPreCondition<TSource, TDestination>
{
var expr = CreatePreConditionExpression(typeof(TCondition));
PreConditionCore(expr);
}
protected Expression<Func<TSource, TDestination, ResolutionContext, bool>> CreatePreConditionExpression(Type conditionType)
{
var srcParam = Parameter(typeof(TSource));
var destParam = Parameter(typeof(TDestination));
var ctxParam = Parameter(typeof(ResolutionContext));
var conditionInstance = ServiceLocator(conditionType);
var interfaceType = conditionType.GetGenericInterface(typeof(IPreCondition<,>)) ??
throw new InvalidOperationException($"Type '{conditionType.Name}' does not implement IPreCondition<TSource, TDestination>");
var evaluateMethod = interfaceType.GetMethod("Evaluate");
// Get the actual types from the interface
var interfaceArgs = interfaceType.GenericTypeArguments;
var expectedSourceType = interfaceArgs[0];
var expectedDestType = interfaceArgs[1];
// Cast parameters to the expected types if needed
var srcArg = typeof(TSource) == expectedSourceType ? srcParam : (Expression)Convert(srcParam, expectedSourceType);
var destArg = typeof(TDestination) == expectedDestType ? destParam : (Expression)Convert(destParam, expectedDestType);
var callExpression = Call(
Convert(conditionInstance, interfaceType),
evaluateMethod,
srcArg, destArg, ctxParam
);
return Lambda<Func<TSource, TDestination, ResolutionContext, bool>>(View on GitHub (pinned to dfa6dd587c)
Solutions
- Implement IPreCondition<TSource, TDestination> on your pre-condition class with the exact same generic type arguments as the mapping.
- Alternatively, use one of the lambda PreCondition(...) overloads (e.g., PreCondition(src => src.IsValid)).
- Verify the generic arguments match the map's TSource and TDestination.
Example fix
// before — wrong interface
public class MyPreCondition : ICondition<Source, Dest, bool> { /* ... */ }
CreateMap<Source, Dest>().ForMember(d => d.X, opt => opt.PreCondition<MyPreCondition>());
// after — correct interface
public class MyPreCondition : IPreCondition<Source, Dest>
{
public bool Evaluate(Source src, Dest dest, ResolutionContext ctx) => src.IsValid;
}
CreateMap<Source, Dest>().ForMember(d => d.X, opt => opt.PreCondition<MyPreCondition>()); Defensive patterns
Strategy: type-guard
Type guard
// Type guard: verify a type implements IPreCondition<TSource, TDestination>
static bool ImplementsPreCondition<TSource, TDestination>(Type preConditionType)
=> preConditionType.GetGenericInterface(typeof(IPreCondition<,>)) != null;
// Usage before configuring
if (!ImplementsPreCondition<Source, Dest>(typeof(MyPreCondition)))
throw new InvalidOperationException($"{nameof(MyPreCondition)} must implement IPreCondition<Source, Dest>."); Prevention
- Always implement IPreCondition<TSource, TDestination> with the exact generic arguments matching the map.
- Prefer lambda PreCondition(...) overloads for simple pre-conditions.
- Run AssertConfigurationIsValid in tests to catch mismatches.
When it happens
Trigger: Calling .PreCondition<MyPreCondition>() inside a ForMember callback where MyPreCondition does not implement IPreCondition<TSource, TDestination>, or implements it with mismatched generic type arguments.
Common situations: Implementing the wrong interface; confusing IPreCondition with ICondition; type argument mismatch between the pre-condition's generic arguments and the mapping's source/destination types.
Related errors
- Type '{conditionType.Name}' does not implement ICondition<TS
- Only interfaces can be proxied. {DestinationType}
- The type {typeMap.DestinationType.Name} does not have a cons
- Only member accesses are allowed. {destinationMember}
- sourceExpression may not be null when mapping {DestinationMe
AI-assisted analysis of LuckyPennySoftware/AutoMapper@dfa6dd587c (2026-08-13).
Data as JSON: /api/errors/b9d4ab511317fa02.
Report an issue: GitHub.