litedb-org/LiteDB · error · LiteException
0
0
Error message
Expression `{expression.Source}` must return a enumerable expression What it means
LiteException (code 0) thrown by LiteCollection.GetIndexExpression when building a multi-key index from a LINQ selector. The selector's return type K is enumerable (e.g. IEnumerable/Array), the expression resolved to a scalar value, and it is not a simple path expression, so LiteDB cannot auto-convert it to the '$.Field[*]' multi-key form. Only simple member-path selectors like x => x.Phones get auto-expanded; computed or transformed enumerables are rejected.
Source
Thrown at LiteDB/Client/Database/Collections/Index.cs:145
/// <summary>
/// Get index expression based on LINQ expression. Convert IEnumerable in MultiKey indexes
/// </summary>
private BsonExpression GetIndexExpression<K>(Expression<Func<T, K>> keySelector, bool convertEnumerableToMultiKey = true)
{
var expression = _mapper.GetIndexExpression(keySelector);
if (convertEnumerableToMultiKey && typeof(K).IsEnumerable() && expression.IsScalar == true)
{
if (expression.Type == BsonExpressionType.Path)
{
// convert LINQ expression that returns an IEnumerable but expression returns a single value
// `x => x.Phones` --> `$.Phones[*]`
// works only if exression is a simple path
expression = expression.Source + "[*]";
}
else
{
throw new LiteException(0, $"Expression `{expression.Source}` must return a enumerable expression");
}
}
return expression;
}
/// <summary>
/// Drop index and release slot for another index
/// </summary>
public bool DropIndex(string name)
{
return _engine.DropIndex(_collection, name);
}
}
}View on GitHub (pinned to f906a5f850)
Solutions
- Index a simple stored enumerable field: EnsureIndex(x => x.Phones) so it rewrites to $.Phones[*].
- If you must index a projection, materialize it into a stored field on the document and index that field.
- Use the string overload EnsureIndex("name", "$.Phones[*]") to express the multi-key path directly.
Example fix
// before
db.GetCollection<User>().EnsureIndex(x => x.Phones.Select(p => p.Number));
// after
db.GetCollection<User>().EnsureIndex(x => x.PhoneNumbers); // stored List<string> field
// or
db.GetCollection<User>().EnsureIndex("phones", "$.Phones[*].Number"); Defensive patterns
Strategy: validation
Validate before calling
// Validate the selector is a simple member path before indexing
Expression<Func<T, IEnumerable<TItem>>> sel = x => x.Phones; // simple path only
// Or use the string overload to be explicit:
collection.EnsureIndex("phones", "$.Phones[*]"); Type guard
static bool IsSimpleMemberPath<T, K>(Expression<Func<T, K>> selector)
=> selector.Body is MemberExpression;
// Usage: only call multi-key EnsureIndex when IsSimpleMemberPath returns true; otherwise index a stored field. Try / catch
try
{
collection.EnsureIndex(x => x.Phones);
}
catch (LiteException ex) when (ex.Message.Contains("must return a enumerable expression"))
{
// fall back to indexing a stored, simple enumerable field
logger.LogWarning("Index selector was not a simple path; index skipped.");
} Prevention
- Index stored enumerable fields, not computed projections.
- Prefer the string overload '$.Field[*]' for explicit multi-key indexes.
- Materialize derived collections into a stored property before indexing.
When it happens
Trigger: Calling EnsureIndex with a LINQ selector whose type K is enumerable but whose body is not a plain member access, e.g. EnsureIndex(x => x.Phones.Select(p => p.Number)) or EnsureIndex(x => x.Tags.Where(...)). The mapper produced a scalar BsonExpression, and because it is not a Path, the [*] rewrite is refused.
Common situations: Indexing a computed/derived collection property; projecting inside the index selector instead of indexing a stored array field; entity with a getter-only computed enumerable that the mapper cannot represent as a path.
Related errors
- Extend expression must return an anonymous class to be merge
- Expression {expr.ToString()} must be a lambda expression
- Operator not supported {nodeType}
- Extend expression must return a document. Eg: `col.UpdateMan
- Multiple OrderBy calls are not supported. Use ThenBy for add
AI-assisted analysis of litedb-org/LiteDB@f906a5f850 (2026-08-13).
Data as JSON: /api/errors/a9c465d027b6e8f6.
Report an issue: GitHub.