laravel/framework · error · InvalidArgumentException
Order direction must be a SortDirection, "asc" or "desc".
Error message
Order direction must be a SortDirection, "asc" or "desc".
What it means
Thrown by orderBy's match expression when $direction is neither a SortDirection enum case nor a string that lowercases to 'asc'/'desc'. Since the enum introduction, only those three normalized values are accepted; typos, localized strings, or uppercase variants with weird casing are caught here (note the code lowercases the string before comparing, so 'ASC' is fine, but 'ascending' or '' is not).
Source
Thrown at src/Illuminate/Database/Query/Builder.php:2992
*/
public function orderBy($column, $direction = SortDirection::Ascending)
{
if ($this->isQueryable($column)) {
[$query, $bindings] = $this->createSub($column);
$column = new Expression('('.$query.')');
$this->addBinding($bindings, $this->unions ? 'unionOrder' : 'order');
}
$direction = match (true) {
$direction instanceof SortDirection => match ($direction) {
SortDirection::Ascending => 'asc',
SortDirection::Descending => 'desc',
},
strtolower($direction) === 'asc' => 'asc',
strtolower($direction) === 'desc' => 'desc',
default => throw new InvalidArgumentException('Order direction must be a SortDirection, "asc" or "desc".'),
};
$this->{$this->unions ? 'unionOrders' : 'orders'}[] = [
'column' => $column,
'direction' => $direction,
];
return $this;
}
/**
* Add a descending "order by" clause to the query.
*
* @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*>|\Illuminate\Contracts\Database\Query\Expression|string $column
* @return $this
*/
public function orderByDesc($column)
{View on GitHub (pinned to bd6b5437e6)
Solutions
- Use the enum: `orderBy('col', SortDirection::Descending)` or the helper `orderByDesc('col')`.
- Whitelist user input: `$dir = in_array(strtolower($req->dir), ['asc','desc']) ? $req->dir : 'asc';`.
- Pass the literal string 'asc' or 'desc'.
- Coerce empty/null to a default before calling orderBy.
Example fix
// before
$query->orderBy('name', $request->input('sort_dir'));
// when sort_dir=ascending => Order direction must be a SortDirection...
// after
$dir = in_array(strtolower((string) $request->input('sort_dir')), ['asc','desc'], true)
? strtolower((string) $request->input('sort_dir'))
: 'asc';
$query->orderBy('name', $dir); Defensive patterns
Strategy: validation
Validate before calling
use Illuminate\Database\Query\SortDirection;
$dir = match (strtolower((string) $input)) {
'asc', 'ascending' => 'asc',
'desc', 'descending' => 'desc',
default => 'asc',
};
$query->orderBy($col, $dir); Type guard
function isValidOrderDirection(mixed $d): bool
{
return $d instanceof \Illuminate\Database\Query\SortDirection
|| in_array(strtolower((string) $d), ['asc','desc'], true);
} Try / catch
// Validate the direction from user input before calling orderBy; do not try/catch.
Prevention
- Forward ?sort_dir through a whitelist of ['asc','desc'] in the controller.
- Prefer the SortDirection enum or orderByDesc/orderBy helpers at call sites.
- Default missing direction input to 'asc' explicitly.
When it happens
Trigger: `orderBy('created_at', 'ascending')`. Passing an empty string default. Passing user-controlled input like `$request->input('dir')` directly as direction. Passing a boolean or integer as direction.
Common situations: Datatables/sortable-table controllers forwarding `?dir=...` straight into orderBy; i18n code returning translated direction words; refactoring away from magic strings to the enum but missing one call site.
Related errors
- A subquery must be a query builder instance, a Closure, or a
- Nested arrays may not be passed to whereIn method.
- The number of columns must match the number of values
- Timeout must be greater than zero.
- You must specify an orderBy clause when using this function.
AI-assisted analysis of laravel/framework@bd6b5437e6 (2026-08-06).
Data as JSON: /data/errors/03570e4c0c03a01c.json.
Report an issue: GitHub.