dotnet/efcore · error · InvalidOperationException
IncompatibleComplexTypesInAssignment
IncompatibleComplexTypesInAssignment
Error message
The complex types '{complexType1}' and '{complexType2}' are being assigned, but the latter is lacking property '{property}' of the former. What it means
When assigning one complex-type column to another (line 549-558), EF looks up a matching complex property by name on the value's complex type. If the value's complex type is missing a complex property that the target has (same CLR type but different model shape, e.g. ShippingAddress vs BillingAddress where only one has a County sub-object), IncompatibleComplexTypesInAssignment is thrown naming the missing property.
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 dbf9771522)
Solutions
- Configure both complex types identically so they have the same set of nested complex properties.
- Instead of assigning one complex column to another, assign scalar properties individually.
- Pass a constant/parameter of the CLR type rather than a cross-column shaper reference so the target's own structure is used.
Example fix
// before (ShippingAddress has nested Region that BillingAddress lacks)
db.Customers.ExecuteUpdate(s => s.SetProperty(
c => c.BillingAddress, c => c.ShippingAddress));
// after (configure both complex types identically, or update scalars)
modelBuilder.Entity<Customer>()
.ComplexProperty(c => c.BillingAddress, a => a.ComplexProperty(x => x.Region))
.ComplexProperty(c => c.ShippingAddress, a => a.ComplexProperty(x => x.Region)); Defensive patterns
Strategy: validation
Validate before calling
// Ensure two complex types share the same nested complex property names before cross-assigning.
var targetNames = targetComplexType.GetComplexProperties().Select(p => p.Name);
var valueNames = valueComplexType.GetComplexProperties().Select(p => p.Name);
var missing = targetNames.Except(valueNames).ToList();
if (missing.Any()) throw new InvalidOperationException($"Value complex type missing: {string.Join(", ", missing)}"); Try / catch
try { await q.ExecuteUpdateAsync(s => s.SetProperty(e => e.Billing, e => e.Shipping)); }
catch (InvalidOperationException ex) when (ex.Message.Contains("lacking property"))
{ /* configure both complex types identically, or assign scalars individually */ } Prevention
- Configure complex types sharing a CLR type with identical nested property sets.
- Prefer assigning scalar sub-properties over whole complex columns.
- Pass a captured constant value so the target's own structure is used.
When it happens
Trigger: SetProperty assigning a value whose StructuralTypeShaperExpression complex type lacks a nested complex property present on the target, e.g. SetProperty(e => e.BillingAddress, e => e.ShippingAddress) where ShippingAddress has a nested complex property that BillingAddress does not.
Common situations: Two complex types sharing the same CLR type but configured differently in the model; partial configuration of one complex type (a property was configured on one but not the other); refactoring where a nested value object was added to one side only.
Related errors
- ExecuteOperationOnOwnedJsonIsNotSupported
- ExecuteUpdateOverJsonIsNotSupported
- ExecuteUpdateCannotSetJsonPropertyToNonJsonColumn
- ExecuteUpdateCannotSetJsonPropertyToArbitraryExpression
- JsonExecuteUpdateNotSupportedWithOwnedEntities
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/39dc92f86db5b084.
Report an issue: GitHub.