laravel/framework · error · InvalidArgumentException

Invalid aggregate [{$aggregate}] used within ofMany relation

Error message

Invalid aggregate [{$aggregate}] used within ofMany relation. Available aggregates: MIN, MAX

What it means

ofMany() on a has-one/has-many relation selects a single representative row by an aggregate (MIN/MAX). The implementation only supports 'min' and 'max' because it builds a deterministic sub-query join; any other aggregate (SUM, AVG, COUNT) is rejected with InvalidArgumentException listing the allowed set.

Source

Thrown at src/Illuminate/Database/Eloquent/Relations/Concerns/CanBeOneOfMany.php:95

        $keyName = $this->query->getModel()->getKeyName();

        $columns = is_string($columns = $column) ? [
            $column => $aggregate,
            $keyName => $aggregate,
        ] : $column;

        if (! array_key_exists($keyName, $columns)) {
            $columns[$keyName] = 'MAX';
        }

        if ($aggregate instanceof Closure) {
            $closure = $aggregate;
        }

        foreach ($columns as $column => $aggregate) {
            if (! in_array(strtolower($aggregate), ['min', 'max'])) {
                throw new InvalidArgumentException("Invalid aggregate [{$aggregate}] used within ofMany relation. Available aggregates: MIN, MAX");
            }

            $subQuery = $this->newOneOfManySubQuery(
                $this->getOneOfManySubQuerySelectColumns(),
                array_merge([$column], $previous['columns'] ?? []),
                $aggregate,
            );

            if (isset($previous)) {
                $this->addOneOfManyJoinSubQuery(
                    $subQuery,
                    $previous['subQuery'],
                    $previous['columns'],
                );
            }

            if (isset($closure)) {
                $closure($subQuery);

View on GitHub (pinned to bd6b5437e6)

Solutions

  1. Use only 'MIN' or 'MAX' for ofMany (e.g. ->ofMany('price', 'MAX') for the most expensive).
  2. For more complex selection, pass a closure to ofMany() and build the sub-query manually.
  3. If you need an average/sum-based representative, compute it separately and select the matching row with a custom where/subquery.

Example fix

// before
return $this->hasOne(Order::class)->ofMany('total', 'AVG');

// after
return $this->hasOne(Order::class)->ofMany('total', 'MAX');
Defensive patterns

Strategy: type-guard

Validate before calling

$aggregate = strtoupper($aggregate);
if (! in_array($aggregate, ['MIN', 'MAX'], true)) {
    throw new \InvalidArgumentException("ofMany supports only MIN/MAX, got {$aggregate}");
}
$relation->ofMany($column, $aggregate);

Type guard

function isValidOfManyAggregate(string $aggregate): bool {
    return in_array(strtoupper($aggregate), ['MIN', 'MAX'], true);
}

Prevention

When it happens

Trigger: Calling ->ofMany('price', 'AVG') or ->ofMany('score', 'sum'), or passing an array of column=>aggregate with a non-min/max value.

Common situations: Wanting an 'average' or 'total' representative row (which ofMany cannot express); copy-paste from SQL with a SUM/AVG; typos or wrong-case aggregates (case is lowercased before check, so case isn't the issue).

Related errors


AI-assisted analysis of laravel/framework@bd6b5437e6 (2026-08-06). Data as JSON: /data/errors/ecf27c1f4ef993f8.json. Report an issue: GitHub.