LuckyPennySoftware/AutoMapper · error · AutoMapperMappingException

Error building constructor projection strategy.

Error message

Error building constructor projection strategy.

What it means

During ProjectTo, ProjectionBuilder.CreateDestination builds the destination via a constructor call, projecting each constructor parameter with TryProjectMember. Any exception other than AutoMapperConfigurationException thrown while resolving a parameter is wrapped in AutoMapperMappingException carrying the failing ConstructorParameterMap and the original as InnerException.

Source

Thrown at src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs:235

                            }
                        }
                        throw CannotMap(memberMap, resolvedSource.Type);
                    }
                }
            }
            NewExpression CreateDestination() => typeMap switch
            {
                { CustomCtorExpression: LambdaExpression ctorExpression } => (NewExpression)ctorExpression.ReplaceParameters(instanceParameter),
                { ConstructorMap: { CanResolve: true } constructorMap } =>
                    New(constructorMap.Ctor, constructorMap.CtorParams.Select(map =>
                    {
                        try
                        {
                            return TryProjectMember(map, map.DefaultValue(null)) ?? Default(map.DestinationType);
                        }
                        catch (Exception e) when (e is not AutoMapperConfigurationException)
                        {
                            throw new AutoMapperMappingException("Error building constructor projection strategy.", e, map);
                        }
                    })),
                _ => New(typeMap.DestinationType)
            };
        }
    }
    static AutoMapperMappingException CannotMap(MemberMap memberMap, Type sourceType) => new(
        $"Unable to create a map expression from {memberMap.SourceMember?.DeclaringType?.Name}.{memberMap.SourceMember?.Name} ({sourceType}) to {memberMap.DestinationType.Name}.{memberMap.DestinationName} ({memberMap.DestinationType})",
        null, memberMap);
    [EditorBrowsable(EditorBrowsableState.Never)]
    sealed class FirstPassLetPropertyMaps(IGlobalConfiguration configuration, MemberPath parentPath, TypePairCount builtProjections) : LetPropertyMaps(configuration, parentPath, builtProjections)
    {
        readonly List<SubQueryPath> _savedPaths = [];
        public override Expression GetSubQueryMarker(LambdaExpression letExpression)
        {
            SubQueryPath subQueryPath = new([.. _currentPath.Reverse()], letExpression);
            var existingPath = _savedPaths.SingleOrDefault(s => s.IsEquivalentTo(subQueryPath));
            if (existingPath.Marker != null)

View on GitHub (pinned to dfa6dd587c)

Solutions

  1. Inspect ex.InnerException and the failing constructor parameter (the map in the exception) to identify which ctor arg broke.
  2. Provide an explicit ForCtorParam("name").MapFrom(...) with an EF-translatable expression, or MapFrom a concrete source member.
  3. Give the parameter a translatable default via ForCtorParam(...).MapFrom, or use a parameterless-constructable destination type.
  4. Ensure nested types referenced by ctor params have their own CreateProjection/CreateMap.

Example fix

// before
CreateProjection<Order, OrderRecord>(); // OrderRecord(int Id, string Label)
var q = ctx.Orders.ProjectTo<OrderRecord>(_cfg).ToList(); // throws: 'Label' ctor param unresolvable

// after
CreateProjection<Order, OrderRecord>()
    .ForCtorParam("Label", o => o.MapFrom(s => s.Name)); // explicit translatable source
var q = ctx.Orders.ProjectTo<OrderRecord>(_cfg).ToList();
Defensive patterns

Strategy: try-catch

Validate before calling

configuration.AssertConfigurationIsValid();
// Additionally, for record/positional destinations, unit-test ProjectTo on an
// in-memory IQueryable so each constructor parameter resolves transitively.

Try / catch

try
{
    result = query.ProjectTo<RecordDest>(_cfg).ToList();
}
catch (AutoMapperMappingException ex) when (ex.Message.Contains("constructor projection strategy"))
{
    var root = ex.InnerException;
    var failingParam = ex.MemberMap?.DestinationName; // ctor param name
    // add an explicit ForCtorParam(...).MapFrom(translatable) and retry
}

Prevention

When it happens

Trigger: ProjectTo onto a type with a parameterized constructor (record, immutable DTO) where a constructor parameter cannot be resolved or translated: ForCtorParam with an untranslatable MapFrom, a ctor param with no matching source member and no usable default, or a nested projection missing its map.

Common situations: Records/positional DTOs with required ctor params; ForCtorParam MapFrom calling unsupported methods; ctor parameter name not matching any source member after a rename; migrating from class-with-setters to records.

Related errors


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