{"record":{"id":"5df701b4737967d0","repo":"dotnet/efcore","slug":"cosmos-sql-does-not-allow-offset-without-limit-co","errorCode":null,"errorMessage":"Cosmos SQL does not allow Offset without Limit. Consider specifying a 'Take' operation on the query.","messagePattern":"Cosmos SQL does not allow Offset without Limit\\. Consider specifying a 'Take' operation on the query\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Cosmos/Query/Internal/CosmosQuerySqlGenerator.cs","lineNumber":440,"sourceCode":"            if (selectExpression.Offset != null)\n            {\n                Visit(selectExpression.Offset);\n            }\n            else\n            {\n                _sqlBuilder.Append('0');\n            }\n\n            _sqlBuilder.Append(\" LIMIT \");\n\n            if (selectExpression.Limit != null)\n            {\n                Visit(selectExpression.Limit);\n            }\n            else\n            {\n                // TODO: See Issue#18923\n                throw new InvalidOperationException(CosmosStrings.OffsetRequiresLimit);\n            }\n        }\n\n        return selectExpression;\n    }\n\n    /// <summary>\n    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to\n    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in\n    ///     any release. You should only use it directly in your code with extreme caution and knowing that\n    ///     doing so can result in application failures when updating to a new Entity Framework Core release.\n    /// </summary>\n    protected virtual Expression VisitFromSql(FromSqlExpression fromSqlExpression)\n    {\n        var sql = fromSqlExpression.Sql;\n\n        string[] substitutions;\n","sourceCodeStart":422,"sourceCodeEnd":458,"githubUrl":"https://github.com/dotnet/efcore/blob/dbf9771522148d61a2467854921bd5dc6f6e6916/src/EFCore.Cosmos/Query/Internal/CosmosQuerySqlGenerator.cs#L422-L458","documentation":"Thrown by CosmosQuerySqlGenerator when emitting OFFSET and selectExpression.Limit is null. Cosmos SQL (the provider's dialect) requires every OFFSET to be paired with a LIMIT, so when a query carries Skip without Take the generator refuses to synthesize an arbitrary limit. The TODO comment references issue #18923 for tracking.","triggerScenarios":"Calling .Skip(n) on a Cosmos query without a following .Take(m), e.g. db.Items.OrderBy(x => x.Id).Skip(50).ToListAsync().","commonSituations":"Pagination code that only skips (page-by-offset without page-size). Reusing a Skip-only helper built for SQL Server against the Cosmos provider.","solutions":["Add a Take(pageSize) after every Skip so the query becomes Skip(n).Take(m).","If you genuinely want all rows after an offset, pass a large explicit Take (e.g. int.MaxValue) — but prefer real pagination with a bounded page size."],"exampleFix":"// before\nvar page = await db.Items\n    .OrderBy(x => x.Id)\n    .Skip(50)\n    .ToListAsync();\n\n// after\nvar page = await db.Items\n    .OrderBy(x => x.Id)\n    .Skip(50)\n    .Take(25)\n    .ToListAsync();","handlingStrategy":"validation","validationCode":"// Guard pagination helpers: require a page size whenever skip > 0\nstatic IQueryable<T> Page<T>(IQueryable<T> q, int skip, int take)\n{\n    if (skip > 0 && take <= 0) throw new ArgumentOutOfRangeException(nameof(take), \"Cosmos requires Take when Skip is used.\");\n    return q.Skip(skip).Take(take);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pair Skip with Take in a single pagination helper so Skip-only is impossible.","For Cosmos, prefer continuation-token / ORDER BY + WHERE key pagination over large offset values."],"tags":["cosmos","ef-core","query","sql-generation","pagination"],"analyzedSha":"dbf9771522148d61a2467854921bd5dc6f6e6916","analyzedAt":"2026-08-06T20:46:03.226Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}