octobercms/october · error · SystemException
Cannot use both limit and pagination.
Error message
Cannot use both limit and pagination.
What it means
ReportQueryBuilder::validate() rejects having both $limit and $pagination set, throwing SystemException('Cannot use both limit and pagination.'). limit caps the row count (TOP N) while pagination implies paged result sets with page/pageSize semantics; combining them would make the resulting SQL ambiguous (limit inside or outside the page window). Set exactly one of the two before the builder validates.
Source
Thrown at modules/dashboard/classes/ReportQueryBuilder.php:677
{
if (!$this->tableName) {
throw new SystemException('Table name is required.');
}
if (!$this->dimension) {
throw new SystemException('Dimension is required.');
}
if (($this->dateStart || $this->dateEnd) && $this->startTimestamp !== null) {
throw new SystemException('Cannot use both date range and timestamp filtering.');
}
if (!$this->dateStart && $this->startTimestamp === null) {
throw new SystemException('Either date range or start timestamp is required.');
}
if ($this->limit !== null && $this->pagination !== null) {
throw new SystemException('Cannot use both limit and pagination.');
}
}
/**
* buildQuery constructs the query builder
*
* @param bool $skipGrouping
* @param bool $skipPagination
* @param array $forceMetrics
* @return QueryBuilder
*/
protected function buildQuery(
bool $skipGrouping = false,
bool $skipPagination = false,
array $forceMetrics = []
): QueryBuilder {
$query = Db::table($this->tableName);
View on GitHub (pinned to b608633a7e)
Solutions
- Keep one mechanism: for a fixed Top N use setLimit($n) and remove pagination setup; for paged output use setPagination($page, $perPage) and remove the limit.
- When loading saved widget properties, unset 'limit' whenever pagination params are present (or vice versa) before configuring the builder.
- Sanitize request input: accept either per_page/page or limit, never merge both into the builder.
- Reset builder state if the same instance is reused for different widgets.
Example fix
// before $builder->setLimit(10)->setPagination(2, 20); // after (Top N) $builder->setLimit(10); // or (paged) // $builder->setPagination(2, 20);
Defensive patterns
Strategy: validation
Validate before calling
$props = $widget->properties;
if (!empty($props['use_pagination'])) {
unset($props['limit']);
$builder->setPagination($page, $perPage);
} else {
unset($props['page'], $props['per_page']);
$builder->setLimit((int) ($props['limit'] ?? 10));
} Prevention
- Decide Top-N vs pagination per widget and strip the other option from merged properties.
- When migrating a widget from limit to pagination, clear stored 'limit' properties for existing users.
- Send either page/per_page or limit from the front-end, never both.
When it happens
Trigger: Calling both $builder->setLimit(10) and $builder->setPagination(...) (or the fluent limit()/paginate() equivalents) on the same builder; a widget config merge that retains a saved 'limit' while the request adds pagination params (e.g. ?page=2&per_page=20).
Common situations: Upgrading a widget from fixed Top-N output to a paginated table while the stored widget properties still contain the old limit value; copy-pasting builder setup between widgets; front-end sending both pageSize and limit keys.
Related errors
- Cannot use both date range and timestamp filtering.
- Cannot switch to container: a container element is not found
- Inspector surface unique ID should be defined.
- Current page is not set for a paginated query
- Table name is required.
AI-assisted analysis of octobercms/october@b608633a7e (2026-08-21).
Data as JSON: /api/errors/bb743ae6354f8fdb.
Report an issue: GitHub.