dotnet/efcore · error · InvalidOperationException

This node should be handled by provider-specific SQL generat

Error message

This node should be handled by provider-specific SQL generator.

What it means

The base relational QuerySqlGenerator.VisitJsonScalar throws by design: JsonScalarExpression nodes must be rewritten/expanded by the provider-specific SQL generator (or eliminated earlier in the pipeline) before reaching this default visitor. Seeing it means a JSON path expression survived into SQL generation unhandled.

Source

Thrown at src/EFCore.Relational/Query/QuerySqlGenerator.cs:1673

            for (var i = 1; i < rowValues.Count; i++)
            {
                if (i > 1)
                {
                    _relationalCommandBuilder.Append(", ");
                }

                Visit(valuesExpression.RowValues[i]);
            }
        }
    }

    /// <summary>
    ///     Generates SQL for a JSON scalar lookup expression.
    /// </summary>
    /// <param name="jsonScalarExpression">The <see cref="JsonScalarExpression" /> for which to generate SQL.</param>
    protected virtual Expression VisitJsonScalar(JsonScalarExpression jsonScalarExpression)
        => throw new InvalidOperationException(
            RelationalStrings.JsonNodeMustBeHandledByProviderSpecificVisitor);

    /// <summary>
    ///     Returns a bool value indicating if the inner SQL expression required to be put inside parenthesis when generating SQL for outer
    ///     SQL expression.
    /// </summary>
    /// <param name="outerExpression">The outer expression which provides context in which SQL is being generated.</param>
    /// <param name="innerExpression">The inner expression which may need to be put inside parenthesis.</param>
    /// <returns>A bool value indicating that parenthesis is required or not. </returns>
    protected virtual bool RequiresParentheses(SqlExpression outerExpression, SqlExpression innerExpression)
    {
        int outerPrecedence, innerPrecedence;

        // Convert is rendered as a function (CAST()) and not as an operator, so we never need to add parentheses around the inner
        if (outerExpression is SqlUnaryExpression { OperatorType: ExpressionType.Convert })
        {
            return false;
        }

View on GitHub (pinned to 3a2006ef56)

Solutions

  1. Use a provider that supports JSON columns for your database (e.g. Microsoft.EntityFrameworkCore.SqlServer with JSON mapping support, Npgsql for PostgreSQL).
  2. Ensure the EF Core relational package and provider package versions match.
  3. If JSON mapping is not required, remap the owned type to a separate column/table or as a complex type.
  4. File an issue against the provider if it claims JSON support but leaves JsonScalarExpression unhandled.

Example fix

// before (provider lacks JSON support)
modelBuilder.Entity<Order>()
    .OwnsOne(o => o.Address, a => a.ToJson());
var city = await db.Orders.Select(o => o.Address.City).ToListAsync();
// after (map as columns instead)
modelBuilder.Entity<Order>()
    .OwnsOne(o => o.Address);  // table columns
var city = await db.Orders.Select(o => o.Address.City).ToListAsync();
Defensive patterns

Strategy: validation

Validate before calling

// Verify the provider advertises JSON support before mapping to JSON.
var providerName = db.Database.ProviderName;
var supportsJson = providerName is
    "Microsoft.EntityFrameworkCore.SqlServer"      // recent versions w/ JSON
    or "Npgsql.EntityFrameworkCore.PostgreSQL";    // jsonb
if (!supportsJson)
    throw new InvalidOperationException($"Provider {providerName} cannot translate JSON-mapped owned entities.");

Prevention

When it happens

Trigger: Querying a JSON-mapped owned property in a way that yields a JsonScalarExpression at SQL-generation time when the provider does not override VisitJsonScalar or did not expand it. Typically with providers/versions that do not support JSON columns (e.g. SQLite without the JSON-owning bits, older SQL Server provider on JSON-mapped entities), or when an internal rewrite pass is skipped.

Common situations: Mapping an owned entity type to JSON (.ToJson()) and then projecting/filtering on its scalar properties under a provider that lacks JSON support; upgrading EF Core without upgrading the provider; using a community provider that has not implemented the JSON visitor.

Related errors


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