litedb-org/LiteDB · error · NotSupportedException

Expression {expr.ToString()} must be a lambda expression

Error message

Expression {expr.ToString()} must be a lambda expression

What it means

Thrown by the LinqExpressionVisitor constructor when the expression passed is not a LambdaExpression. The visitor needs a lambda to extract its root parameter, which drives all downstream member-access resolution. Without a lambda there is no parameter context to translate against.

Source

Thrown at LiteDB/Client/Mapper/Linq/LinqExpressionVisitor.cs:60

        private readonly BsonDocument _parameters = new BsonDocument();
        private int _paramIndex = 0;
        private Type _dbRefType = null;

        private readonly StringBuilder _builder = new StringBuilder();
        private readonly Stack<MemberExpression> _memberAccessNodes = new();

        public LinqExpressionVisitor(BsonMapper mapper, Expression expr)
        {
            _mapper = mapper;
            _expr = expr;

            if (expr is LambdaExpression lambda)
            {
                _rootParameter = lambda.Parameters.First();
            }
            else
            {
                throw new NotSupportedException($"Expression {expr.ToString()} must be a lambda expression");
            }
        }

        public BsonExpression Resolve(bool predicate)
        {
            this.Visit(_expr);

            ENSURE(_memberAccessNodes.Count == 0, "Member access node stack must be empty when finish expression resolve");

            var expression = _builder.ToString();

            try
            {
                var e = BsonExpression.Create(expression, _parameters);

                // if expression must return an predicate but expression result is Path/Parameter/Call add `= true`
                if (predicate && (e.Type == BsonExpressionType.Path || e.Type == BsonExpressionType.Call || e.Type == BsonExpressionType.Parameter))
                {

View on GitHub (pinned to f906a5f850)

Solutions

  1. Always pass a lambda expression (x => x.Something) to the LINQ query APIs (Find, Query.Where, etc.).
  2. Do not construct LinqExpressionVisitor directly; use BsonMapper.GetExpression or GetIndexExpression.
  3. If subclassing BsonMapper, ensure any override that builds a LinqExpressionVisitor passes a lambda expression.
Defensive patterns

Strategy: type-guard

Validate before calling

// Ensure the expression is a lambda before passing to query APIs
static void EnsureLambda<T>(Expression<T> expr)
{
    if (expr is not LambdaExpression)
        throw new ArgumentException("Expression must be a lambda.", nameof(expr));
}

Type guard

// Type guard: Expression<Func<T,K>> is always a lambda at the type level.
// If building expressions dynamically:
static bool IsLambdaExpression(Expression expr) => expr is LambdaExpression;

Try / catch

try
{
    var bsonExpr = mapper.GetExpression<MyEntity, bool>(predicate);
}
catch (NotSupportedException ex) when (ex.Message.Contains("must be a lambda expression"))
{
    throw new InvalidOperationException("Query predicate must be a lambda expression.", ex);
}

Prevention

When it happens

Trigger: Constructing a LinqExpressionVisitor with an Expression that is not a LambdaExpression (e.g., a bare MemberExpression, ConstantExpression, or MethodCallExpression).

Common situations: Effectively unreachable from the public API surface: GetExpression<T,K> and GetIndexExpression<T,K> both accept Expression<Func<T,K>> which is always a lambda. Could surface if the visitor is instantiated via reflection or in a custom BsonMapper subclass that passes a raw non-lambda Expression.

Related errors


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