litedb-org/LiteDB · error · LiteException

0

0

Error message

Expression `{this.Source}` is not a scalar expression and can return more than one result

What it means

Thrown by BsonExpression.ExecuteScalar when the expression's IsScalar flag is false, meaning the expression can yield zero or more values per document (an enumerable/path expression). ExecuteScalar demands a single-value (scalar) expression. This is a LiteException with code 0.

Source

Thrown at LiteDB/Document/Expression/BsonExpression.cs:274

        public BsonValue ExecuteScalar(IEnumerable<BsonDocument> source, Collation collation = null)
        {
            if (source == null) throw new ArgumentNullException(nameof(source));

            return this.ExecuteScalar(source, null, null, collation);
        }

        /// <summary>
        /// Execute expression and returns IEnumerable values - returns NULL if no elements
        /// </summary>
        internal BsonValue ExecuteScalar(IEnumerable<BsonDocument> source, BsonDocument root, BsonValue current, Collation collation)
        {
            if (this.IsScalar)
            {
                return _funcScalar(source, root, current, collation ?? Collation.Binary, this.Parameters);
            }
            else
            {
                throw new LiteException(0, $"Expression `{this.Source}` is not a scalar expression and can return more than one result");
            }
        }

        #endregion

        #region Static method

        private static readonly ConcurrentDictionary<string, BsonExpressionEnumerableDelegate> _cacheEnumerable = new ConcurrentDictionary<string, BsonExpressionEnumerableDelegate>();
        private static readonly ConcurrentDictionary<string, BsonExpressionScalarDelegate> _cacheScalar = new ConcurrentDictionary<string, BsonExpressionScalarDelegate>();

        /// <summary>
        /// Parse string and create new instance of BsonExpression - can be cached
        /// </summary>
        public static BsonExpression Create(string expression)
        {
            return Create(expression, new BsonDocument());
        }

View on GitHub (pinned to f906a5f850)

Solutions

  1. Check `expr.IsScalar` before calling ExecuteScalar; if false, use the enumerable execution path (Execute) instead.
  2. Rewrite the expression to produce a single value, e.g., wrap with an aggregate (MIN, MAX, COUNT) or select a specific index `$.items[0]`.
  3. Validate user-supplied expression strings at parse time using BsonExpression.Create and inspect IsScalar.

Example fix

// before
var result = expr.ExecuteScalar(docs);
// after
var result = expr.IsScalar
    ? expr.ExecuteScalar(docs)
    : expr.Execute(docs).FirstOrDefault() ?? BsonValue.Null;
Defensive patterns

Strategy: validation

Validate before calling

if (!expr.IsScalar) throw new InvalidOperationException($"Expression '{expr.Source}' is not scalar; use Execute() instead.");
var result = expr.ExecuteScalar(source);

Type guard

static bool IsScalarExpression(BsonExpression expr) => expr != null && expr.IsScalar;

Try / catch

try { return expr.ExecuteScalar(source); }
catch (LiteException ex) when (ex.Message.Contains("not a scalar expression"))
{ /* fall back to enumerable execution or report to caller */ }

Prevention

When it happens

Trigger: Calling ExecuteScalar on an expression containing array paths (e.g., `$.items[*]`), MAP, FILTER, or any operator that produces multiple results. Using a multi-result expression where a single value is required (e.g., in a BETWEEN bound, an index key, or a scalar aggregation slot).

Common situations: Building dynamic expressions where the user-supplied query contains a wildcard or multi-value path, then calling ExecuteScalar. Using an aggregate-style expression in a scalar context. Expression caching where a previously enumerable expression is reused in a scalar call site.

Related errors


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