mongodb/laravel-mongodb · error · InvalidArgumentException
Cannot sort by '_score' in ascending order; Atlas Search…
Error message
Cannot sort by '_score' in ascending order; Atlas Search relevance score always sorts descending.
What it means
Atlas Search relevance scores are always ranked descending (highest score first). The Scout engine rejects an explicit ascending '_score' sort with an InvalidArgumentException, validated before any I/O.
Solutions
- Remove the '_score' order or force its direction to 'desc'
- For lowest-relevance-first results, sort desc by _score and reverse the page client-side (or use $searchMeta differently)
- Filter user-supplied sort directions so '_score' is always mapped to 'desc'
- Catch InvalidArgumentException and fall back to relevance-descending order
Example fix
// before
$builder->orderBy('_score', $dir); // $dir may be 'asc'
// after
$builder->orderBy('_score', 'desc'); // relevance is always descending Defensive patterns
Strategy: validation
Validate before calling
foreach ($builder->orders as $o) {
if ($o['column'] === '_score' && $o['direction'] === 'asc') {
throw new InvalidArgumentException("'_score' must sort descending.");
}
} Try / catch
try {
$builder->orderBy('_score', $dir);
} catch (\InvalidArgumentException $e) {
$builder->orderBy('_score', 'desc'); // coerce relevance to descending
} Prevention
- Whitelist 'desc' as the only direction for '_score' in sort-building code
- Clamp user-supplied directions instead of passing them through
- Write a unit test covering every UI-selectable sort direction
When it happens
Trigger: Calling search()/paginate() with ->orderBy('_score', 'asc') on the Scout builder; any code path that adds an ascending order whose column is '_score'.
Common situations: Building dynamic sort UIs where the user can pick asc/desc without excluding the relevance column; defaulting all sorts to asc.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Cannot sort by a field named 'score' together with Atlas…
- Invalid search index definition for collection
- Atlas search index operation time out after
- The MongoDB Scout collection
- Between $values must be a list with exactly two elements…
AI-assisted analysis of mongodb/laravel-mongodb@0634653039 (2026-09-15).
Data as JSON: /api/errors/9eb987d74e4852cc.
Report an issue: GitHub.
Appendix: source
Thrown at src/Scout/ScoutEngine.php:209
$builder->take($perPage);
return $this->performSearch($builder, $perPage * ($page - 1));
}
/**
* Perform the given search on the engine.
*/
private function performSearch(Builder $builder, ?int $offset = null): array
{
// Validate sort before any I/O so unit tests can assert on these exceptions without a real collection.
$columns = array_column($builder->orders, 'column');
if (in_array('_score', $columns, true) && in_array('score', $columns, true)) {
throw new InvalidArgumentException("Cannot sort by a field named 'score' together with Atlas Search's '_score' relevance sort.");
}
foreach ($builder->orders as $order) {
if ($order['column'] === '_score' && $order['direction'] === 'asc') {
throw new InvalidArgumentException("Cannot sort by '_score' in ascending order; Atlas Search relevance score always sorts descending.");
}
}
$collection = $this->getSearchableCollection($builder->model);
if ($builder->callback) {
$cursor = call_user_func(
$builder->callback,
$collection,
$builder->query,
$offset,
);
assert($cursor instanceof CursorInterface, new LogicException(sprintf('The search builder closure must return a MongoDB cursor, %s returned', get_debug_type($cursor))));
$cursor->setTypeMap(self::TYPEMAP);
return $cursor->toArray();
}
View on GitHub (pinned to 0634653039)