dotnet/efcore · error · InvalidOperationException
Complex projections in subqueries are currently unsupported.
Error message
Complex projections in subqueries are currently unsupported.
What it means
When SelectExpression.AddJoin folds a subquery into a JOIN, it must map the inner query's projection into the outer projection. For scalar inner projections this works, but when an inner projection emits a JSON object (complex/owned value or anonymous object) there is no way to reference that object across the JOIN (tracked as TODO #34004), so it throws InvalidOperationException.
Source
Thrown at src/EFCore.Cosmos/Query/Internal/Expressions/SelectExpression.cs:599
{
SqlExpression e => new ScalarReferenceExpression(joinSource.Alias, e.Type, e.TypeMapping),
StructuralTypeProjectionExpression e => e.Update(new ObjectReferenceExpression(e.StructuralType, joinSource.Alias)),
_ => throw new UnreachableException(
$"Unexpected expression type in projection when adding join: {expression.GetType().Name}")
};
}
else
{
// TODO: #34004
// The subquery is projecting out a JSON object; for the projection mapping of the outer query, we need to generate
// property accesses over that object: Scalar/ObjectAccessExpressions over the ObjectReferenceExpression that references
// the JOIN source.
// However, the JSON object being projected out of the subquery doesn't correspond to any entity type, and there's currently
// no way for us to represent a reference to that - ObjectReferenceExpression requires an IEntityType. Changing that
// requires shaper-side changes (see comment in ObjectReferenceExpression); if we can remove that requirement, we can
// possibly also merge ScalarReferenceExpression and ObjectReferenceExpression to a single SourceReferenceExpression.
throw new InvalidOperationException(CosmosStrings.ComplexProjectionInSubqueryNotSupported);
}
projectionMapping[remappedProjectionMember] = projectionToAdd;
}
innerSelect.ApplyProjection();
_sources.Add(joinSource);
innerShaper = new ProjectionMemberRemappingExpressionVisitor(this, mapping).Visit(innerShaper);
_projectionMapping = projectionMapping;
innerSelect._projectionMapping.Clear();
return New(
transparentIdentifierType.GetTypeInfo().DeclaredConstructors.Single(),
[outerShaper, innerShaper], outerMemberInfo, innerMemberInfo);
}
/// <summary>View on GitHub (pinned to dbf9771522)
Solutions
- Project scalar properties out of the inner subquery instead of whole objects (e.g. Select(x => x.Name) rather than selecting the entity).
- Restructure the query to avoid the join (fetch roots then load related data separately).
- Materialize the relevant entities client-side with separate queries and stitch them in memory.
Example fix
// before
var q = from o in ctx.Orders
from c in ctx.Customers.Where(c => c.Id == o.CustomerId).Select(c => c.Address)
select new { o, c };
// after: project scalars from the inner subquery
var q = from o in ctx.Orders
from c in ctx.Customers.Where(c => c.Id == o.CustomerId)
select new { o.Id, City = c.Address.City }; Defensive patterns
Strategy: validation
Validate before calling
// Project scalars from the inner side of joins to avoid complex subquery projections.
static IQueryable<TResult> JoinScalar<TOuter, TInner, TKey, TResult>(
IQueryable<TOuter> outer, IQueryable<TInner> inner,
Expression<Func<TOuter, TKey>> ok, Expression<Func<TInner, TKey>> ik,
Expression<Func<TOuter, TInner, TResult>> sel)
where TResult : class // ensure TResult is built from scalars, not whole objects
=> outer.Join(inner, ok, ik, sel); Try / catch
try { var q = query.ToList(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("Complex projections in subqueries"))
{ /* project scalars or load client-side */ } Prevention
- Project scalar fields from inner subqueries, not whole entities.
- Prefer separate queries stitched client-side for complex join shapes.
When it happens
Trigger: A LINQ query whose join/select-many inner source projects a complex or owned object (non-scalar) rather than scalar fields — e.g. joining and then projecting whole embedded entities from the inner side.
Common situations: Complex projections inside joins; projecting owned types out of a joined subquery; advanced SelectMany shapes ported from relational providers.
Related errors
- The query uses 'NoTrackingWithIdentityResolution' and projec
- The LINQ expression '{expression}' could not be translated.
- The LINQ expression '{expression}' could not be translated.
- Unhandled expression node type '{nodeType}'.
- Cannot translate '{comparisonOperator}' on a subquery expres
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/48a387676a65bb85.
Report an issue: GitHub.