dotnet/efcore · error · InvalidOperationException

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

Error message

'ExecuteUpdate' cannot currently set a property in a JSON column to a regular, non-JSON column; see https://github.com/dotnet/efcore/issues/36688.

What it means

Thrown inside the JsonScalarExpression case when TrySerializeScalarToJson fails and the value being assigned is a ColumnExpression. EF Core cannot set a JSON column's nested property to the value of a different, non-JSON column — the JSON modification functions only accept JSON-serialized scalars. Tracked by issue #36688.

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)

Solutions

  1. Split the operation: read the source value first, then ExecuteUpdate with a parameter/constant serialized into the JSON path.
  2. Restructure so the JSON property is updated from a constant or parameter only (supported paths).
  3. Track #36688 for future support of column-to-JSON assignments.

Example fix

// before
await ctx.Set<Root>().ExecuteUpdateAsync(s =>
    s.SetProperty(r => r.Config.Enabled, r => r.TmpFlag));
// after
var flag = await ctx.Set<Root>().Select(r => r.TmpFlag).FirstAsync();
await ctx.Set<Root>().ExecuteUpdateAsync(s =>
    s.SetProperty(r => r.Config.Enabled, flag));
Defensive patterns

Strategy: validation

Validate before calling

// Detect column-source value selectors into JSON paths.
// Heuristic: if the value selector references a property of a different entity/table than the JSON owner, read it first.
var src = await ctx.Set<Root>().Select(r => r.TmpFlag).FirstAsync();
await ctx.Set<Root>().ExecuteUpdateAsync(s => s.SetProperty(r => r.Config.Enabled, src));

Prevention

When it happens

Trigger: ExecuteUpdate with SetProperty pointing at a JSON scalar path and a value selector that projects a column from another table: SetProperty(e => e.JsonConfig.SomeFlag, e => e.OtherEntity.SomeFlag). The Sqlite tests (SqliteMiscellaneousTypeTest, SqliteTemporalTypeTest) assert this message.

Common situations: Trying to copy a value from a relational column into a JSON path in one ExecuteUpdate; cross-column assignments involving JSON.

Related errors


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