dotnet/efcore · error · InvalidOperationException
ExecuteUpdateCannotSetJsonPropertyToArbitraryExpression
ExecuteUpdateCannotSetJsonPropertyToArbitraryExpression
Error message
'ExecuteUpdate' cannot currently set a property in a JSON column to arbitrary expressions; only constants, parameters and other JSON properties are supported; see https://github.com/dotnet/efcore/issues/36688.
What it means
Same JSON-scalar setter path (line 371-400), but here the value is neither a ColumnExpression nor one of the supported shapes (constant, parameter, or another JsonScalarExpression). TrySerializeScalarToJson returns false for arbitrary expressions, so the else branch at line 391-394 throws ExecuteUpdateCannotSetJsonPropertyToArbitraryExpression (issue #36688). Only constants, parameters, and JSON-to-JSON property copies are supported.
Source
Thrown at src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.ExecuteUpdate.cs:391
var typeMapping = jsonScalar.TypeMapping;
Check.DebugAssert(typeMapping is not null);
// We should never see a JsonScalarExpression without a path - that means we're mapping a JSON scalar directly to a relational column.
// This is in theory possible (e.g. map a DateTime to a 'json' column with a single string timestamp representation inside, instead of to
// SQL Server datetime2), but contrived and unsupported.
Check.DebugAssert(jsonScalar.Path.Count > 0);
ProcessColumn(jsonColumn, targetProperty);
var translatedValue = TranslateScalarSetterValueSelector(source, valueSelector, jsonScalar.Type, typeMapping);
// We now have the relational scalar expression for the value; but we need the JSON representation to pass to the provider's JSON modification
// function (e.g. SQL Server JSON_MODIFY()).
// For example, for a DateTime we'd have e.g. a SqlConstantExpression containing a DateTime instance, but we need a string containing
// the JSON-encoded ISO8601 representation.
if (!TrySerializeScalarToJson(jsonScalar, translatedValue, out var jsonValue))
{
throw new InvalidOperationException(
translatedValue is ColumnExpression
? RelationalStrings.ExecuteUpdateCannotSetJsonPropertyToNonJsonColumn
: RelationalStrings.ExecuteUpdateCannotSetJsonPropertyToArbitraryExpression);
}
// We now have a serialized JSON value (number, string or bool) - generate a setter for it.
GenerateJsonPartialUpdateSetterWrapper(jsonScalar, jsonColumn, jsonValue);
continue;
}
case StructuralTypeShaperExpression { ValueBufferExpression: JsonQueryExpression jsonQuery }:
ProcessStructuralJsonSetter(jsonQuery);
continue;
case CollectionResultExpression { QueryExpression: JsonQueryExpression jsonQuery }:
ProcessStructuralJsonSetter(jsonQuery);
continue;
View on GitHub (pinned to dbf9771522)
Solutions
- Read the current value client-side, compute the new value, and pass it as a constant/parameter.
- Use raw SQL with the database's JSON modification function (e.g. JSON_MODIFY) for server-side computation.
- Restrict JSON-scalar SetProperty values to literals, captured variables (parameters), or another JSON scalar property copy.
Example fix
// before (arithmetic on a JSON path is not supported)
db.Blogs.ExecuteUpdate(s => s.SetProperty(
b => b.Json.ViewCount, b => b.Json.ViewCount + 1));
// after (compute client-side, pass as a parameter)
var current = await db.Blogs.Where(b => b.Id == id)
.Select(b => b.Json.ViewCount).FirstAsync();
db.Blogs.Where(b => b.Id == id)
.ExecuteUpdate(s => s.SetProperty(
b => b.Json.ViewCount, current + 1)); Defensive patterns
Strategy: validation
Try / catch
try { await q.ExecuteUpdateAsync(s => s.SetProperty(e => e.Json.Counter, e => e.Json.Counter + 1)); }
catch (InvalidOperationException ex) when (ex.Message.Contains("arbitrary expressions"))
{ /* compute client-side and pass as parameter; or use raw SQL JSON functions */ } Prevention
- Restrict JSON scalar SetProperty values to constants, parameters, or JSON-to-JSON property copies.
- Compute increments/transformations client-side before ExecuteUpdate.
- Reserve server-side JSON math for raw SQL where the DB supports it.
When it happens
Trigger: Assigning a computed/arbitrary expression to a JSON scalar: SetProperty(e => e.Json.Counter, e => e.Json.Counter + 1), SetProperty(e => e.Json.Score, e => SomeMethod()), or any function-call/arithmetic expression targeting a JSON path.
Common situations: Trying to increment a JSON counter server-side; calling EF.Functions or custom methods in the value lambda for a JSON property; combining columns/JSON values arithmetically into a JSON target.
Related errors
- ExecuteUpdateCannotSetJsonPropertyToNonJsonColumn
- ExecuteOperationOnOwnedJsonIsNotSupported
- ExecuteUpdateOverJsonIsNotSupported
- IncompatibleComplexTypesInAssignment
- JsonExecuteUpdateNotSupportedWithOwnedEntities
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/5409cba02b5d80d3.
Report an issue: GitHub.