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
- Use a provider that supports JSON columns for your database (e.g. Microsoft.EntityFrameworkCore.SqlServer with JSON mapping support, Npgsql for PostgreSQL).
- Ensure the EF Core relational package and provider package versions match.
- If JSON mapping is not required, remap the owned type to a separate column/table or as a complex type.
- 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
- Match EF Core relational and provider package versions.
- Map owned types to columns/tables unless you specifically need JSON and your provider supports it.
- File a provider issue if JSON support is claimed but VisitJsonScalar is unhandled.
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
- SelectExpression can only be built over a JsonQueryExpressio
- '{operation}' used over owned type '{entityType}' which is m
- The LINQ expression '{expression}' could not be translated.
- Unable to translate set operation after client projection ha
- 'DefaultIfEmpty' cannot be applied after a client-evaluated
AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11).
Data as JSON: /api/errors/e966b496ab0e427d.
Report an issue: GitHub.