dotnet/efcore · error · NotSupportedException

Unhandled expression node type

Error message

Unhandled expression node type '{nodeType}'.

What it means

CosmosShapedQueryCompilingExpressionVisitor expects the ShapedQueryExpression's QueryExpression to be a Cosmos SelectExpression. If it is any other Expression subtype (e.g. a relational SelectExpression leak, or a custom shaper that wraps a different query expression), the visitor throws NotSupportedException CoreStrings.UnhandledExpressionNode.

Solutions

  1. Ensure the DbContext and the DbSet both use the Cosmos provider end-to-end.
  2. Do not share compiled queries or expression trees across providers.
  3. If extending the query pipeline, always return a Cosmos SelectExpression from your visitor.
Defensive patterns

Strategy: validation

Validate before calling

// ensure provider consistency
static void AssertCosmos(DbContext ctx)
{
    if (ctx.Database.ProviderName != "Microsoft.EntityFrameworkCore.Cosmos")
        throw new InvalidOperationException("Context is not using the Cosmos provider.");
}

Type guard

static bool IsCosmosContext(DbContext ctx)
    => ctx.Database.ProviderName == "Microsoft.EntityFrameworkCore.Cosmos";

Prevention

When it happens

Trigger: A ShapedQueryExpression whose QueryExpression is not the Cosmos SelectExpression — typically from mixing providers in one query, custom IQueryCompiler extensions, or reusing a compiled query across providers.

Common situations: Running a query compiled against a relational context through a Cosmos context, sharing query compilation code across providers, or third-party EF extensions that build ShapedQueryExpression manually.

Related errors


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

Appendix: source

Thrown at src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.cs:62

        var (paging, maxItemCount, continuationToken, responseContinuationTokenLimitInKb) =
            (false, (SqlParameterExpression)null, (SqlParameterExpression)null, (SqlParameterExpression)null);

        // If the query is terminated ToPageAsync(), CosmosQueryableMethodTranslatingExpressionVisitor composed a PagingExpression on top
        // of the shaper. We remove that to get the shaper for each actual document being read (as opposed to the page of those documents),
        // and extract the pagination arguments.
        if (shaperBody is PagingExpression pagingExpression)
        {
            paging = true;
            maxItemCount = pagingExpression.MaxItemCount;
            continuationToken = pagingExpression.ContinuationToken;
            responseContinuationTokenLimitInKb = pagingExpression.ResponseContinuationTokenLimitInKb;

            shaperBody = pagingExpression.Expression;
        }

        if (shapedQueryExpression.QueryExpression is not SelectExpression selectExpression)
        {
            throw new NotSupportedException(CoreStrings.UnhandledExpressionNode(shapedQueryExpression.QueryExpression));
        }

        VerifyNoClientConstant(shaperBody);

        // Because the shaper might process the data twice (duplicated shaper),
        // we pass the data as ROM, and the shaper will create a JsonReaderData where needed.
        var dataParameter = Parameter(typeof(ReadOnlyMemory<byte>), "data");
        // The shaper will always read the whole next json token/object, and will know how many bytes that was
        // we get the amount of bytes read from the shaper, so that we can advance the data in the QueryingEnumerable as needed, without having to scan the data twice (once for shaper, once for advancing the data).
        var bytesConsumedParameter = Parameter(typeof(int).MakeByRefType(), "bytesConsumed");
        var shaperLambda = new ShaperProcessingExpressionVisitor(this, selectExpression, dataParameter, bytesConsumedParameter)
            .ProcessShaper(shaperBody);

        var cosmosQueryContextConstant = Convert(QueryCompilationContext.QueryContextParameter, typeof(CosmosQueryContext));
        var shaperConstant = Constant(shaperLambda.Compile());
        var contextTypeConstant = Constant(_contextType);
        var rootEntityTypeConstant = Constant(rootEntityType);
        var threadSafetyConstant = Constant(_threadSafetyChecksEnabled);

View on GitHub (pinned to 3a2006ef56)