laravel/framework · error · RuntimeException
You must specify an orderBy clause when using this function.
Error message
You must specify an orderBy clause when using this function.
What it means
enforceOrderBy() is called by methods whose result is only meaningful with a deterministic row order — forPage(), skip()/take() with an offset, and a few cursor-style helpers. If neither $this->orders nor $this->unionOrders is populated, it throws RuntimeException, because paginating an unordered query returns arbitrary (and unstable) rows.
Solutions
- Add ->orderBy('id') (or another deterministic column) before paginate()/forPage()/skip().
- Order by a unique, monotonic column to make pagination stable across pages.
- If you truly want unordered rows, fetch without skip/take.
Example fix
// before
User::forPage($page, $size)->get();
// after
User::orderBy('id')->forPage($page, $size)->get(); Defensive patterns
Strategy: validation
Validate before calling
if (empty($query->orders) && empty($query->unionOrders)) {
$query->orderBy('id');
}
$query->forPage($page, $size); Prevention
- Always call orderBy() on a unique/monotonic column before paginate()/forPage()/skip().
- Add a repository-level convention that all paged queries start with a deterministic order.
- Test pagination with a seeded dataset to catch missing orderBy early.
When it happens
Trigger: ->forPage(2, 15) or ->skip(10)->take(5) on a query that has no prior orderBy() call.
Common situations: Adding pagination to an existing query and forgetting the order; relying on default insertion order which DBs do not guarantee; paginating a query that previously used an index but now does a full scan.
Related errors
- Order direction must be a SortDirection, "asc" or "desc".
- The chunkById operation was aborted because the
- The lazyById operation was aborted because the
- A subquery must be a query builder instance, a Closure, or…
- $count records were found.
AI-assisted analysis of laravel/framework@e0f6eb3518 (2026-08-11).
Data as JSON: /api/errors/e6570e8c8b1e3935.
Report an issue: GitHub.
Appendix: source
Thrown at src/Illuminate/Database/Query/Builder.php:3811
yield from $this->connection->cursor(
$this->toSql(), $this->getBindings(), ! $this->useWritePdo, $this->fetchUsing
);
}))->map(function ($item) {
return $this->applyAfterQueryCallbacks(new Collection([$item]))->first();
})->reject(fn ($item) => is_null($item));
}
/**
* Throw an exception if the query doesn't have an orderBy clause.
*
* @return void
*
* @throws \RuntimeException
*/
protected function enforceOrderBy()
{
if (empty($this->orders) && empty($this->unionOrders)) {
throw new RuntimeException('You must specify an orderBy clause when using this function.');
}
}
/**
* Get a collection instance containing the values of a given column.
*
* @param \Illuminate\Contracts\Database\Query\Expression|string $column
* @param string|null $key
* @return \Illuminate\Support\Collection<array-key, mixed>
*/
public function pluck($column, $key = null)
{
$original = $this->columns;
// First, we will need to select the results of the query accounting for the
// given columns / key. Once we have the results, we will be able to take
// the results and get the exact data that was requested for the query.
$this->columns ??= is_null($key) || $key === $columnView on GitHub (pinned to e0f6eb3518)