dotnet/efcore · error · InvalidOperationException

'ExecuteUpdate' cannot currently set a property in a JSON…

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

Sibling of 606, same JsonScalarExpression case of TrySerializeScalarToJson failing, but here the translatedValue is NOT a ColumnExpression — it is some arbitrary SQL expression the JSON serializer cannot handle. JSON modification functions only accept constants, parameters, or other JSON properties.

Solutions

  1. Compute the value in application code and pass it as a parameter/constant.
  2. Restrict JSON-setter value selectors to constants, captured variables (parameters), or another JSON property reference.
  3. Track #36688 for broader expression support.

Example fix

// before
.ExecuteUpdate(s => s.SetProperty(e => e.Config.Score, e => e.A + e.B));
// after
var score = a + b;
.ExecuteUpdate(s => s.SetProperty(e => e.Config.Score, score));
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the JSON value selector is a constant, parameter, or JSON property reference.
var value = ComputeScore();
await ctx.Set<Root>().ExecuteUpdateAsync(s => s.SetProperty(e => e.Config.Score, value));

Prevention

When it happens

Trigger: SetProperty into a JSON scalar path whose value selector translates to a function call, arithmetic, or any non-constant/non-parameter expression (e.g. SetProperty(e => e.Config.Score, e => e.A + e.B)).

Common situations: Computing the new JSON value inline; using database functions inside the value selector of a JSON setter.

Related errors


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

Appendix: 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 3a2006ef56)