{"record":{"id":"a9c465d027b6e8f6","repo":"litedb-org/LiteDB","slug":"0","errorCode":"0","errorMessage":"Expression `{expression.Source}` must return a enumerable expression","messagePattern":"Expression `(.+?)` must return a enumerable expression","errorType":"exception","errorClass":"LiteException","httpStatus":null,"severity":"error","filePath":"LiteDB/Client/Database/Collections/Index.cs","lineNumber":145,"sourceCode":"        /// <summary>\n        /// Get index expression based on LINQ expression. Convert IEnumerable in MultiKey indexes\n        /// </summary>\n        private BsonExpression GetIndexExpression<K>(Expression<Func<T, K>> keySelector, bool convertEnumerableToMultiKey = true)\n        {\n            var expression = _mapper.GetIndexExpression(keySelector);\n\n            if (convertEnumerableToMultiKey && typeof(K).IsEnumerable() && expression.IsScalar == true)\n            {\n                if (expression.Type == BsonExpressionType.Path)\n                {\n                    // convert LINQ expression that returns an IEnumerable but expression returns a single value\n                    // `x => x.Phones` --> `$.Phones[*]`\n                    // works only if exression is a simple path\n                    expression = expression.Source + \"[*]\";\n                }\n                else\n                {\n                    throw new LiteException(0, $\"Expression `{expression.Source}` must return a enumerable expression\");\n                }\n            }\n\n            return expression;\n        }\n\n        /// <summary>\n        /// Drop index and release slot for another index\n        /// </summary>\n        public bool DropIndex(string name)\n        {\n            return _engine.DropIndex(_collection, name);\n        }\n    }\n}","sourceCodeStart":127,"sourceCodeEnd":160,"githubUrl":"https://github.com/litedb-org/LiteDB/blob/f906a5f850678719e39a39a006cb66dcae563cfa/LiteDB/Client/Database/Collections/Index.cs#L127-L160","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\ndb.GetCollection<User>().EnsureIndex(x => x.Phones.Select(p => p.Number));\n\n// after\ndb.GetCollection<User>().EnsureIndex(x => x.PhoneNumbers); // stored List<string> field\n// or\ndb.GetCollection<User>().EnsureIndex(\"phones\", \"$.Phones[*].Number\");","handlingStrategy":"validation","validationCode":"// Validate the selector is a simple member path before indexing\nExpression<Func<T, IEnumerable<TItem>>> sel = x => x.Phones; // simple path only\n// Or use the string overload to be explicit:\ncollection.EnsureIndex(\"phones\", \"$.Phones[*]\");","typeGuard":"static bool IsSimpleMemberPath<T, K>(Expression<Func<T, K>> selector)\n    => selector.Body is MemberExpression;\n// Usage: only call multi-key EnsureIndex when IsSimpleMemberPath returns true; otherwise index a stored field.","tryCatchPattern":"try\n{\n    collection.EnsureIndex(x => x.Phones);\n}\ncatch (LiteException ex) when (ex.Message.Contains(\"must return a enumerable expression\"))\n{\n    // fall back to indexing a stored, simple enumerable field\n    logger.LogWarning(\"Index selector was not a simple path; index skipped.\");\n}","preventionTips":["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."],"tags":["index","linq","expression","multi-key","liteexception"],"backgroundTag":null,"analyzedSha":"f906a5f850678719e39a39a006cb66dcae563cfa","analyzedAt":"2026-08-13T21:56:30.148Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}