dotnet/efcore · error · InvalidOperationException
Cosmos SQL does not allow Offset without Limit. Consider…
Error message
Cosmos SQL does not allow Offset without Limit. Consider specifying a 'Take' operation on the query.
What it means
Cosmos SQL syntax requires that any OFFSET clause be paired with a LIMIT clause. The CosmosQuerySqlGenerator emits OFFSET and then a LIMIT token, and when a SelectExpression carries an Offset but no Limit it throws InvalidOperationException at runtime during SQL generation. This is a hard restriction of the Cosmos DB SQL API surface, not an EF choice.
Solutions
- Add a .Take(pageSize) immediately after every .Skip(skip) in the query chain.
- Cap the skip with a sane Take (e.g. int.MaxValue) if you genuinely want all remaining rows after the offset.
- If paging is optional, ensure Take is only omitted when Skip is also omitted.
Example fix
// before var page = db.Users.Skip(20).ToList(); // after var page = db.Users.Skip(20).Take(10).ToList();
Defensive patterns
Strategy: validation
Validate before calling
// before executing, assert every Skip is paired with Take
static IQueryable<T> Paged<T>(IQueryable<T> q, int skip, int? take)
{
var withSkip = q.Skip(skip);
return take is { } t ? withSkip.Take(t) : withSkip.Take(int.MaxValue);
} Prevention
- Wrap paging in a helper that always emits Take alongside Skip.
- Add a unit test that asserts every paging overload produces a Take call.
- Reject null/zero page size at the API boundary rather than dropping Take.
When it happens
Trigger: A LINQ query uses .Skip(n) (which becomes Offset) without a following .Take(m) (which becomes Limit), and that query is executed against the Cosmos provider. EF cannot infer a safe default upper bound, so it refuses to emit OFFSET-only SQL.
Common situations: Pagination code that only forwards a page offset, hand-rolled paging that splits Skip/Take across conditional branches, or third-party paging helpers that omit Take when page size is null.
Related errors
- Unhandled expression
- A FromSqlExpression has an invalid arguments expression type
- Bind property on structural type coming out of scalar…
- Cannot translate ' ' on a subquery expression of entity…
- Cannot translate the
AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11).
Data as JSON: /api/errors/5df701b4737967d0.
Report an issue: GitHub.
Appendix: source
Thrown at src/EFCore.Cosmos/Query/Internal/CosmosQuerySqlGenerator.cs:440
if (selectExpression.Offset != null)
{
Visit(selectExpression.Offset);
}
else
{
_sqlBuilder.Append('0');
}
_sqlBuilder.Append(" LIMIT ");
if (selectExpression.Limit != null)
{
Visit(selectExpression.Limit);
}
else
{
// TODO: See Issue#18923
throw new InvalidOperationException(CosmosStrings.OffsetRequiresLimit);
}
}
return selectExpression;
}
/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
protected virtual Expression VisitFromSql(FromSqlExpression fromSqlExpression)
{
var sql = fromSqlExpression.Sql;
string[] substitutions;
View on GitHub (pinned to 3a2006ef56)