dotnet/efcore · error · InvalidOperationException
The 'setPropertyCalls' argument to 'ExecuteUpdate' may only
Error message
The 'setPropertyCalls' argument to 'ExecuteUpdate' may only contain a chain of 'SetProperty' expressing the properties to be updated.
What it means
Thrown in PrecompiledQueryCodeGenerator.ProcessExecuteUpdate (line 1250, using RelationalStrings.InvalidArgumentToExecuteUpdate) while precompiling an ExecuteUpdate call. EF walks the lambda passed to ExecuteUpdate expecting an inside-out chain of UpdateSettersBuilder<T>.SetProperty(...) calls; as soon as it encounters a node that is not such a SetProperty call it throws. The 'setPropertyCalls' argument may only express the properties to update via SetProperty.
Source
Thrown at src/EFCore.Design/Query/Internal/PrecompiledQueryCodeGenerator.cs:1250
{
if (valueSelector is UnaryExpression
{
NodeType: ExpressionType.Quote,
Operand: LambdaExpression unwrappedValueSelector
})
{
settersBuilder.SetProperty(propertySelector, unwrappedValueSelector);
}
else
{
settersBuilder.SetProperty(propertySelector, valueSelector);
}
expression = methodCallExpression.Object;
continue;
}
throw new InvalidOperationException(RelationalStrings.InvalidArgumentToExecuteUpdate);
}
// The expression tree is nested inside-out (last SetProperty call is the outermost node),
// so setters were added in reverse order. Reverse to restore source code order.
var settersArray = settersBuilder.BuildSettersExpression();
return Expression.NewArrayInit(settersArray.Type.GetElementType()!, settersArray.Expressions.Reverse());
}
private static ITypeSymbol GetTypeSymbol(Compilation compilation, Type type)
{
if (type.IsByRef || type.IsPointer || type.IsGenericParameter || type.IsByRefLike)
{
throw new NotSupportedException($"Unsupported type: {type}");
}
if (type.IsArray)
{
var elementSymbol = GetTypeSymbol(compilation, type.GetElementType()!);View on GitHub (pinned to dbf9771522)
Solutions
- Ensure the ExecuteUpdate setters lambda is strictly a chain of s.SetProperty(x => x.Prop, value) calls with no other operations in between.
- Move any computation out of the setters lambda: compute the value in a variable before ExecuteUpdate and reference it inside SetProperty.
- If you need SetProperty overloads, use the property-selector + value-selector forms that EF's UpdateSettersBuilder provides.
- Exclude the ExecuteUpdate query from precompilation if it cannot be reduced to a pure SetProperty chain.
Example fix
// before: non-SetProperty node inside the setters chain
await db.Blogs.Where(b => b.Id == id)
.ExecuteUpdateAsync(s => s.SetProperty(b => b.Updated, DateTime.Now).AlsoDoSomething());
// after: pure SetProperty chain, value computed beforehand
var now = DateTime.Now;
await db.Blogs.Where(b => b.Id == id)
.ExecuteUpdateAsync(s => s.SetProperty(b => b.Updated, now)); Defensive patterns
Strategy: validation
Validate before calling
// Validate the ExecuteUpdate setters lambda is a pure SetProperty chain before precompiling
static bool IsPureSetPropertyChain(LambdaExpression lambda)
{
var param = lambda.Parameters.Single();
var body = lambda.Body;
while (body != param)
{
if (body is MethodCallExpression mc
&& mc.Method.Name == nameof(UpdateSettersBuilder<int>.SetProperty))
body = mc.Object;
else return false;
}
return true;
} Try / catch
try { /* precompile ExecuteUpdate query */ }
catch (InvalidOperationException ex) when (ex.Message.Contains("ExecuteUpdate"))
{ /* move computations out of the setters; rebuild as a pure SetProperty chain */ } Prevention
- Write ExecuteUpdate setters as a pure chain of SetProperty calls only.
- Compute values in variables before ExecuteUpdate.
- Do not interleave other method calls in the setters lambda.
When it happens
Trigger: Precompiling a query whose ExecuteUpdate setters lambda contains anything other than a chain of SetProperty calls (e.g. an inline computation, a nested method call, an assignment, or a SetProperty variant with a different signature/declaring type). The while loop walking expression != settersParameter fails to match the SetProperty pattern and falls through to the throw.
Common situations: Writing ExecuteUpdate(s => s.SetProperty(x => x.Foo, expr).SetProperty(...)) where expr or an intermediate node is not a quoted SetProperty call. Mixing other method calls into the setters chain. Using a custom SetProperty-like helper instead of EF's SetProperty. A malformed expression tree produced by an older/different EF version.
Related errors
- Encountered non-quotable expression of type {node.GetType()}
- Couldn't find method symbol for: {memberAccessSyntax}
- Couldn't get interceptable location for: '{node}'.
- Generic method on generic type not supported
- Non-extension static method not supported
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/88f8f9abf2dd94df.
Report an issue: GitHub.