dotnet/efcore · error · InvalidOperationException

'DefaultIfEmpty' cannot be applied after a client-evaluated

Error message

'DefaultIfEmpty' cannot be applied after a client-evaluated projection. Consider applying 'DefaultIfEmpty' before last 'Select' or use 'AsEnumerable' before 'DefaultIfEmpty' to apply it on client-side.

What it means

ApplyDefaultIfEmpty throws when _clientProjections.Count != 0 (InMemoryQueryExpression.cs:461-463). DefaultIfEmpty needs the server-side structure intact to synthesise the empty/default row; after a client-evaluated projection that structure is gone.

Source

Thrown at src/EFCore.InMemory/Query/Internal/InMemoryQueryExpression.cs:463

        {
            throw new InvalidOperationException(InMemoryStrings.SetOperationsNotAllowedAfterClientEvaluation);
        }

        ServerQueryExpression = Call(
            setOperationMethodInfo.MakeGenericMethod(typeof(ValueBuffer)), ServerQueryExpression, source2.ServerQueryExpression);
    }

    /// <summary>
    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
    ///     any release. You should only use it directly in your code with extreme caution and knowing that
    ///     doing so can result in application failures when updating to a new Entity Framework Core release.
    /// </summary>
    public virtual void ApplyDefaultIfEmpty()
    {
        if (_clientProjections.Count != 0)
        {
            throw new InvalidOperationException(InMemoryStrings.DefaultIfEmptyAppliedAfterProjection);
        }

        ServerQueryExpression = Call(
            EnumerableMethods.DefaultIfEmptyWithArgument.MakeGenericMethod(typeof(ValueBuffer)),
            ServerQueryExpression,
            Constant(new ValueBuffer(Enumerable.Repeat((object?)null, _projectionMappingExpressions.Count).ToArray())));

        ReplaceProjection(
            _projectionMapping.ToDictionary(
                kv => kv.Key,
                kv => kv.Value switch
                {
                    EntityProjectionExpression p => MakeEntityProjectionNullable(p),

                    var p when !p.Type.IsNullableType()
                        => Coalesce(
                            MakeReadValueNullable(p),
                            p.Type.GetDefaultValueConstant()),

View on GitHub (pinned to dbf9771522)

Solutions

  1. Move DefaultIfEmpty before the last Select so it operates on server-evaluated data.
  2. Use AsEnumerable() before DefaultIfEmpty to apply it client-side.
  3. Replace manual DefaultIfEmpty with a navigation or GroupJoin which EF can translate.

Example fix

// before
var q = db.Blogs.Select(b => new Dto(b)).DefaultIfEmpty();
// after
var q = db.Blogs.DefaultIfEmpty().Select(b => b == null ? null : new Dto(b));
Defensive patterns

Strategy: try-catch

Try / catch

try
{
    var r = query.Select(proj).DefaultIfEmpty().ToList();
}
catch (InvalidOperationException ex) when (ex.Message.Contains("DefaultIfEmpty"))
{
    var r = query.AsEnumerable().Select(proj).DefaultIfEmpty().ToList();
}

Prevention

When it happens

Trigger: Calling DefaultIfEmpty() after a Select that causes client evaluation, e.g. db.Blogs.Select(b => new Dto(b)).DefaultIfEmpty().

Common situations: Manually implementing left-join semantics with Select(...).DefaultIfEmpty(), or applying DefaultIfEmpty on a projected collection. Often appears when translating hand-written SQL left joins to LINQ.

Related errors


AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06). Data as JSON: /api/errors/215f3a2302602e8e. Report an issue: GitHub.