LuckyPennySoftware/AutoMapper · error · ArgumentException

Expression '{lambdaExpression}' must resolve to top-level me

Error message

Expression '{lambdaExpression}' must resolve to top-level member and not any child object's properties. You can use ForPath, a custom resolver on the child type or the AfterMap option instead.

What it means

Thrown by ReflectionHelper.FindProperty when a lambda passed to ForMember (or ForSourceMember) does not resolve to a single top-level property or field of the lambda parameter. The method walks the expression body; it accepts only a MemberExpression whose Expression is the parameter (or a UnaryExpression wrapping one). Any nested access like d => d.Child.Property falls through to the default arm. The message explicitly suggests using ForPath, a custom resolver, or AfterMap instead.

Source

Thrown at src/AutoMapper/Internal/ReflectionHelper.cs:98

            }
        }
        return members;
        static Type GetCurrentType(Type type) => type.IsGenericType && type.IsCollection() ? type.GenericTypeArguments[0] : type;
    }
    public static MemberInfo FindProperty(LambdaExpression lambdaExpression)
    {
        Expression expressionToCheck = lambdaExpression.Body;
        while (true)
        {
            switch (expressionToCheck)
            {
                case MemberExpression { Member: var member, Expression.NodeType: ExpressionType.Parameter or ExpressionType.Convert }:
                    return member;
                case UnaryExpression { Operand: var operand }:
                    expressionToCheck = operand;
                    break;
                default:
                    throw new ArgumentException(
                        $"Expression '{lambdaExpression}' must resolve to top-level member and not any child object's properties. You can use ForPath, a custom resolver on the child type or the AfterMap option instead.",
                        nameof(lambdaExpression));
            }
        }
    }
    public static Type GetMemberType(this MemberInfo member) => member switch
    {
        PropertyInfo property => property.PropertyType,
        MethodInfo method => method.ReturnType,
        FieldInfo field => field.FieldType,
        null => throw new System.ArgumentNullException(nameof(member)),
        _ => throw new ArgumentOutOfRangeException(nameof(member))
    };
}

View on GitHub (pinned to dfa6dd587c)

Solutions

  1. Use ForPath(d => d.Child.Property, opt => opt.MapFrom(s => s.SourceProp)) for nested destination paths.
  2. Use a custom IValueResolver on the child type's map to set the nested property.
  3. Use AfterMap to imperatively set nested destination properties after mapping.

Example fix

// before — nested access in ForMember
CreateMap<Source, Dest>()
    .ForMember(d => d.Address.City, opt => opt.MapFrom(s => s.City));

// after — use ForPath for nested destination
CreateMap<Source, Dest>()
    .ForPath(d => d.Address.City, opt => opt.MapFrom(s => s.City));
Defensive patterns

Strategy: validation

Validate before calling

// Check whether a ForMember lambda is a top-level member access before using it
static bool IsTopLevelMember<TDest, TMember>(Expression<Func<TDest, TMember>> expr)
{
    var body = expr.Body;
    if (body is UnaryExpression u) body = u.Operand;
    return body is MemberExpression me && me.Expression == expr.Parameters[0];
}
// If false, use ForPath instead of ForMember

Prevention

When it happens

Trigger: Calling .ForMember(d => d.Child.Property, opt => ...) to map into a nested destination property. ForMember only accepts top-level members of TDestination.

Common situations: Trying to flatten or un-flatten into a nested destination object; confusing ForMember (flat) with ForPath (nested path); migrating from manual mapping to AutoMapper and attempting nested writes.

Related errors


AI-assisted analysis of LuckyPennySoftware/AutoMapper@dfa6dd587c (2026-08-13). Data as JSON: /api/errors/49511f8df21cbdf5. Report an issue: GitHub.