dotnet/efcore · error · NotImplementedException

Subquery with index projection binding

Error message

Subquery with index projection binding

What it means

Thrown by the Cosmos SQL translator when a subquery's shaped result exposes its projection by positional index instead of by named ProjectionMember. The provider only knows how to remap member-based projection bindings across subquery boundaries, so this is an unimplemented translation path (NotImplementedException) rather than a configuration error. It is an internal API surface and indicates the Cosmos provider has not yet implemented this query shape.

Solutions

  1. Rewrite the query to flatten nested subqueries so the projection is member-based.
  2. Insert AsEnumerable() (or ToListAsync()) before the subquery so it evaluates on the client.
  3. Project scalar members directly inside the subquery instead of through a complex shaper.
  4. File an issue on the dotnet/efcore repo with a minimal repro so the Cosmos team can implement the path.

Example fix

// before
var q = await db.Users
    .Where(u => u.Posts.Select(p => p.Title).Any(t => t.StartsWith("x")))
    .ToListAsync();

// after - move the subquery predicate to the client
var users = await db.Users.ToListAsync();
var q = users
    .Where(u => u.Posts.Select(p => p.Title).Any(t => t.StartsWith("x")))
    .ToList();
Defensive patterns

Strategy: fallback

Validate before calling

// No public API to pre-check; detect unsupported subquery shapes by
// wrapping exploratory queries in try/catch and falling back to AsEnumerable.
public static async Task<List<T>> SafeQuery<T>(IQueryable<T> query)
{
    try { return await query.ToListAsync(); }
    catch (NotImplementedException) { return query.AsEnumerable().ToList(); }
}

Try / catch

try { result = await query.ToListAsync(); }
catch (NotImplementedException ex) when (ex.Message.Contains("Subquery"))
{ result = await query.AsAsyncEnumerable().ToListAsync(); }

Prevention

When it happens

Trigger: Translating a LINQ query where a SelectExpression subquery has an index-based (positional) projection binding (mappedProjectionBindingExpression.ProjectionMember is null). This typically arises from complex nested subqueries, certain GroupBy shapes, or SelectMany patterns where the query compiler builds index-bound shapers.

Common situations: Complex nested subqueries; subqueries introduced by Any/All/Select over navigation collections that fall back to index projection; queries generated by query rewriters that emit positional projection bindings.

Related errors


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

Appendix: source

Thrown at src/EFCore.Cosmos/Query/Internal/CosmosSqlTranslatingExpressionVisitor.cs:455

                if (mappedProjectionBindingExpression == null
                    && shaperExpression is BlockExpression
                    {
                        Expressions: [BinaryExpression { NodeType: ExpressionType.Assign, Right: ProjectionBindingExpression pbe2 }, _]
                    })
                {
                    mappedProjectionBindingExpression = pbe2;
                }

                if (mappedProjectionBindingExpression == null)
                {
                    return QueryCompilationContext.NotTranslatedExpression;
                }

                var subquery = (SelectExpression)shapedQuery.QueryExpression;

                var projection = mappedProjectionBindingExpression.ProjectionMember is { } projectionMember
                    ? subquery.GetMappedProjection(projectionMember)
                    : throw new NotImplementedException("Subquery with index projection binding");
                if (projection is not SqlExpression sqlExpression)
                {
                    return QueryCompilationContext.NotTranslatedExpression;
                }

                if (subquery.Sources.Count == 0)
                {
                    return sqlExpression;
                }

                // TODO TODO
                // subquery.ReplaceProjection(new List<Expression> { sqlExpression });
                subquery.ApplyProjection();

                // Add VALUE to the subquery's projection (SELECT VALUE x ...), to make it project that value rather than a JSON object
                // wrapping that value.
                subquery = subquery.WithSingleValueProjection();

View on GitHub (pinned to 3a2006ef56)