dotnet/efcore · error · InvalidOperationException

The complex types ' ' and ' ' are being assigned, but the…

Error message

The complex types '{complexType1}' and '{complexType2}' are being assigned, but the latter is lacking property '{property}' of the former.

What it means

Thrown when assigning one complex type to another during ExecuteUpdate and the value (right-hand) complex type is missing a property that exists on the target (left-hand) complex type. Because complex types are structurally compared property-by-property, an asymmetric shape is rejected.

Solutions

  1. Make both complex types structurally identical (add the missing property to the value complex type, or remove it from the target).
  2. Assign property-by-property instead of whole-complex-type assignment.
  3. If using the same CLR type for both, ensure model configuration defines the same set of properties on each complex type.

Example fix

// before
.ExecuteUpdate(s => s.SetProperty(e => e.ShippingAddress, e => e.BillingAddress));
// ShippingAddress has Zip, BillingAddress does not
// after
modelBuilder.Entity<Order>().ComplexProperty(o => o.BillingAddress, b => b.Property(x => x.Zip).IsRequired());
// or assign field by field
.ExecuteUpdate(s => s
    .SetProperty(e => e.ShippingAddress.Street, e => e.BillingAddress.Street)
    .SetProperty(e => e.ShippingAddress.City, e => e.BillingAddress.City));
Defensive patterns

Strategy: validation

Validate before calling

// Assert two complex types have identical property sets before assignment.
static bool AreShapeCompatible(IComplexType a, IComplexType b)
{
    var ap = a.GetProperties().Select(p => p.Name).ToHashSet();
    var bp = b.GetProperties().Select(p => p.Name).ToHashSet();
    return ap.SetEquals(bp);
}

Prevention

When it happens

Trigger: SetProperty(e => e.ShippingAddress, e => e.BillingAddress) where ShippingAddress and BillingAddress are different complex types that share a CLR type but one is missing a property defined on the other (e.g. ShippingAddress has Zip but BillingAddress does not). The nested-complex-property lookup returns null and fires this.

Common situations: Using two distinct complex types with the same CLR type but different property sets; refactoring one complex type without updating the other; assigning between complex types that drifted in schema.

Related errors


AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11). Data as JSON: /api/errors/a37a711885ee264e. Report an issue: GitHub.

Appendix: source

Thrown at src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.ExecuteUpdate.cs:554

                    {
                        throw new InvalidOperationException(
                            RelationalStrings.ExecuteUpdateOverJsonIsNotSupported(nestedTargetComplexProperty.ComplexType.DisplayName()));
                    }

                    var nestedTargetExpression =
                        (StructuralTypeShaperExpression)targetProjection.BindComplexProperty(nestedTargetComplexProperty);

                    // If the value expression is a shaper with its own complex type (as opposed to a constant/parameter), we're assigning
                    // one (modeled) column to another. In that case, find the corresponding property on the value complex type (which is
                    // different than the target complex type, despite the two having the same CLR type, e.g. compare ShippingAddress to
                    // BillingAddress).
                    // Otherwise, if the value expression is a constant/parameter, just use the target complex property.
                    var nestedValueComplexProperty = valueExpression is StructuralTypeShaperExpression
                    {
                        StructuralType: IComplexType valueNestedComplexType
                    }
                        ? valueNestedComplexType!.FindComplexProperty(nestedTargetComplexProperty.Name)
                        ?? throw new InvalidOperationException(
                            RelationalStrings.IncompatibleComplexTypesInAssignment(
                                targetNestedComplexType.DisplayName(), valueNestedComplexType.DisplayName(),
                                nestedTargetComplexProperty.Name))
                        : nestedTargetComplexProperty;

                    var nestedValueExpression = CreateComplexPropertyAccessExpression(valueExpression, nestedValueComplexProperty);

                    ProcessComplexType(nestedTargetExpression, nestedValueExpression);
                }

                Expression CreatePropertyAccessExpression(Expression target, IProperty property)
                {
                    return target is LambdaExpression lambda
                        ? Expression.Lambda(Core(lambda.Body, property), lambda.Parameters[0])
                        : Core(target, property);

                    Expression Core(Expression target, IProperty property)
                    {

View on GitHub (pinned to 3a2006ef56)