{"record":{"id":"0e890d593b2bbb21","repo":"litedb-org/LiteDB","slug":"0-0e890d","errorCode":"0","errorMessage":"OrderBy/GroupBy operation are supported only in virtual collection with less than {VIRTUAL_INDEX_MAX_CACHE} documents","messagePattern":"OrderBy/GroupBy operation are supported only in virtual collection with less than (.+?) documents","errorType":"exception","errorClass":"LiteException","httpStatus":null,"severity":"warning","filePath":"LiteDB/Engine/Query/IndexQuery/IndexVirtual.cs","lineNumber":64,"sourceCode":"                {\n                    _cache[rawId] = doc;\n\n                    if (_cache.Count > VIRTUAL_INDEX_MAX_CACHE) _cache = null;\n                }\n\n                // return an fake indexNode\n                yield return new IndexNode(doc);\n            }\n        }\n\n        public BsonDocument Load(IndexNode node)\n        {\n            return node.Key as BsonDocument;\n        }\n\n        public BsonDocument Load(PageAddress rawId)\n        {\n            if (_cache == null) throw new LiteException(0, $\"OrderBy/GroupBy operation are supported only in virtual collection with less than {VIRTUAL_INDEX_MAX_CACHE} documents\");\n\n            return _cache[rawId.PageID];\n        }\n\n        public override string ToString()\n        {\n            return string.Format(\"FULL COLLECTION SCAN\");\n        }\n    }\n}","sourceCodeStart":46,"sourceCodeEnd":74,"githubUrl":"https://github.com/litedb-org/LiteDB/blob/f906a5f850678719e39a39a006cb66dcae563cfa/LiteDB/Engine/Query/IndexQuery/IndexVirtual.cs#L46-L74","documentation":"Thrown by IndexVirtual.Load(PageAddress) when an OrderBy or GroupBy operation requires document lookup from a virtual (in-memory/external) collection, but the internal cache has been nulled because the source exceeded VIRTUAL_INDEX_MAX_CACHE (2000) documents. IndexVirtual caches source documents by rawId up to 2000 entries to support OrderBy/GroupBy lookups; past that limit the cache is dropped to bound memory, and any subsequent lookup that needs it fails.","triggerScenarios":"Running a query with .OrderBy() or .GroupBy() over an external/virtual source (e.g. a system collection, a $dump, or a manually-supplied IEnumerable<BsonDocument> in IndexVirtual) that yields more than 2000 documents. The cache is discarded after the 2000th document; a later OrderBy/GroupBy phase triggers Load(PageAddress) and throws.","commonSituations":"Sorting or grouping large in-memory result sets passed as an external source; querying system collections ($dump, $sequences) with ORDER BY over more than 2000 rows; using ILiteCollection.Query over a virtual source.","solutions":["Reduce the source to fewer than 2000 documents before applying OrderBy/GroupBy (filter first).","Perform the ordering/grouping in application code (LINQ) before/instead of in the LiteDB query.","If using a real (non-virtual) collection, ensure the query uses a physical index so IndexVirtual is not used.","Paginate the virtual source with Limit/Offset to stay under the cache threshold."],"exampleFix":"// before — virtual source too large for ORDER BY\nvar docs = LoadExternalDocs(); // 5000 docs\nvar q = db.GetCollection(\"$dump\").Query().OrderBy(\"$.name\").ToEnumerable();\n// throws during enumeration\n\n// after — sort in app, or filter/paginate first\nvar sorted = docs.OrderBy(d => d[\"name\"]).ToList();\n// or paginate: .Limit(2000) before OrderBy","handlingStrategy":"validation","validationCode":"const int VIRTUAL_MAX = 2000;\n\npublic List<BsonDocument> QueryExternal(LiteDatabase db, IEnumerable<BsonDocument> source)\n{\n    var materialized = source.Take(VIRTUAL_MAX + 1).ToList();\n    if (materialized.Count > VIRTUAL_MAX)\n    {\n        // Source is too large for in-DB OrderBy/GroupBy — sort in app code instead.\n        materialized = source.OrderBy(d => d[\"name\"].AsString).ToList();\n        return materialized;\n    }\n    // Safe to use virtual collection with OrderBy.\n    return db.GetCollection(\"$dump\").InsertBulk(materialized) > 0\n        ? db.GetCollection(\"$dump\").Query().OrderBy(\"$.name\").ToList()\n        : materialized;\n}","typeGuard":"static bool IsSafeForVirtualOrderBy(IEnumerable<BsonDocument> source)\n{\n    // Only safe if you can cheaply count; otherwise cap with Take.\n    return source.Take(2001).Count() <= 2000;\n}","tryCatchPattern":"try\n{\n    var results = virtualQuery.OrderBy(\"$.name\").ToList();\n}\ncatch (LiteException ex) when (ex.Message.Contains(\"virtual collection with less than\"))\n{\n    // Fall back to in-memory LINQ ordering over a materialized list.\n    results = source.OrderBy(d => d[\"name\"].AsString).ToList();\n}","preventionTips":["Keep virtual/external sources under 2000 documents for OrderBy/GroupBy.","Filter (Where) and paginate before ordering on virtual collections.","Prefer real collections with physical indexes for large sorted queries.","Sort large external sources in application code (LINQ)."],"tags":["query","orderby","groupby","virtual-collection","schema-limit","litedb-engine"],"backgroundTag":null,"analyzedSha":"f906a5f850678719e39a39a006cb66dcae563cfa","analyzedAt":"2026-08-13T21:56:30.148Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}