litedb-org/LiteDB · error · ArgumentException

Extend expression must return an anonymous class to be merge

Error message

Extend expression must return an anonymous class to be merge with entities. Eg: `col.UpdateMany(x => new { Name = x.Name.ToUpper() }, x => x.Age > 10)`

What it means

ArgumentException thrown by the LINQ overload of UpdateMany when the extend expression does not resolve to a Document BsonExpression. The method merges the current entity with an anonymous-class initializer (x => new { Name = x.Name.ToUpper() }); if the mapper converts the lambda to a non-document expression, the merge target is undefined and the call is rejected.

Source

Thrown at LiteDB/Client/Database/Collections/Update.cs:82

            return _engine.UpdateMany(_collection, transform, predicate);
        }

        /// <summary>
        /// Update many document based on merge current document with extend expression. Use your class with initializers. 
        /// Eg: col.UpdateMany(x => new Customer { Name = x.Name.ToUpper(), Salary: 100 }, x => x.Name == "John")
        /// </summary>
        public int UpdateMany(Expression<Func<T, T>> extend, Expression<Func<T, bool>> predicate)
        {
            if (extend == null) throw new ArgumentNullException(nameof(extend));
            if (predicate == null) throw new ArgumentNullException(nameof(predicate));

            var ext = _mapper.GetExpression(extend);
            var pred = _mapper.GetExpression(predicate);

            if (ext.Type != BsonExpressionType.Document)
            {
                throw new ArgumentException("Extend expression must return an anonymous class to be merge with entities. Eg: `col.UpdateMany(x => new { Name = x.Name.ToUpper() }, x => x.Age > 10)`");
            }

            return _engine.UpdateMany(_collection, ext, pred);
        }
    }
}

View on GitHub (pinned to f906a5f850)

Solutions

  1. Return an anonymous object with the fields to merge: UpdateMany(x => new { Name = x.Name.ToUpper() }, x => x.Age > 10).
  2. Ensure every member you want to change is a property assignment inside the new { } initializer.
  3. If updating the whole entity, use Update instead of UpdateMany.

Example fix

// before
collection.UpdateMany(x => x.Name.ToUpper(), x => x.Age > 10);

// after
collection.UpdateMany(x => new { Name = x.Name.ToUpper() }, x => x.Age > 10);
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the extend lambda returns an anonymous initializer
// Compile-time guidance: the lambda body should be a NewExpression
Expression<Func<T, T>> ext = x => new { Name = x.Name.ToUpper() }; // anonymous object
// Validate at runtime via the mapper before calling UpdateMany:
var bsonExpr = mapper.GetExpression(ext);
if (bsonExpr.Type != BsonExpressionType.Document)
{
    throw new InvalidOperationException("Extend lambda must project an anonymous object.");
}

Type guard

static bool IsAnonymousInit<TSource>(Expression<Func<TSource, TSource>> extend)
    => extend.Body is NewExpression;

Try / catch

try
{
    collection.UpdateMany(extend, predicate);
}
catch (ArgumentException ex) when (ex.Message.Contains("anonymous class"))
{
    logger.LogError("UpdateMany extend lambda must return new { ... }.");
    throw;
}

Prevention

When it happens

Trigger: Passing a lambda that returns a scalar or a non-anonymous type the mapper cannot treat as a document, e.g. UpdateMany(x => x.Name.ToUpper(), x => x.Age > 10); or returning a single value instead of a member-initializer new { ... }.

Common situations: Using a projection that returns a primitive instead of an anonymous object; returning the entity type itself in a way the mapper collapses to a scalar; confusing the merge extend lambda with a value setter.

Related errors


AI-assisted analysis of litedb-org/LiteDB@f906a5f850 (2026-08-13). Data as JSON: /api/errors/2f8fde80a186fb37. Report an issue: GitHub.