mongodb/laravel-mongodb · error · InvalidArgumentException

The aggregate column name must be a string.

Error message

The aggregate column name must be a string.

What it means

withAggregate() requires the aggregate column to be a string (the field being aggregated). Non-string values (arrays, ints, nulls) throw InvalidArgumentException because MongoDB aggregation field names must be strings.

Solutions

  1. Pass a single string column name, e.g. 'total'
  2. If aggregating multiple columns, call withAggregate once per column
  3. Cast/validate dynamic column values with is_string() before calling
  4. Don't pass null — ensure the config/env default produces a string

Example fix

// before
$query->withAggregate('orders', 'sum', ['total', 'tax']);
// after
$query->withAggregate('orders', 'sum', 'total');
$query->withAggregate('orders', 'sum', 'tax');
Defensive patterns

Strategy: type-guard

Validate before calling

if (!is_string($column)) {
    throw new InvalidArgumentException('Column must be a string');
}

Type guard

function isStringColumn(mixed $column): bool {
    return is_string($column) && $column !== '';
}

Try / catch

try {
    $query->withAggregate('orders', 'sum', $column);
} catch (InvalidArgumentException $e) {
    if (str_contains($e->getMessage(), 'must be a string')) {
        Log::error('withAggregate column must be a string', ['column' => $column]);
    } else {
        throw $e;
    }
}

Prevention

When it happens

Trigger: Calling $query->withAggregate('relation', 'sum', 42) or passing an array of columns / null / an object as the column argument.

Common situations: Copying SQL usage where multiple columns could be passed; dynamic column built from config that resolves to null; misunderstanding the signature and passing an array of columns.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of mongodb/laravel-mongodb@0634653039 (2026-09-15). Data as JSON: /api/errors/0a97765b19a8a830. Report an issue: GitHub.

Appendix: source

Thrown at src/Helpers/QueriesRelationshipAggregates.php:70

    private array $withAggregates = [];

    /** @inheritdoc */
    public function withAggregate($relations, $column, $function = null)
    {
        if (empty($relations)) {
            return $this;
        }

        if (! in_array($function, self::AGGREGATE_FUNCTIONS, true)) {
            throw new InvalidArgumentException(sprintf(
                'Aggregate function "%s" is not supported by MongoDB. Supported functions are: %s.',
                $function ?? 'null',
                implode(', ', self::AGGREGATE_FUNCTIONS),
            ));
        }

        if (! is_string($column)) {
            throw new InvalidArgumentException('The aggregate column name must be a string.');
        }

        if (str_starts_with($column, '$')) {
            throw new InvalidArgumentException(sprintf(
                'The aggregate column name "%s" must not start with "$".',
                $column,
            ));
        }

        foreach ($this->parseWithRelations(is_array($relations) ? $relations : [$relations]) as $name => $constraints) {
            [$name, $alias] = $this->resolveAggregateAlias($name, $function, $column);

            $relation = $this->getRelationWithoutConstraints($name);
            $this->assertAggregateRelationSupported($relation, $name);
            $this->assertEmbeddedConstraintsSupported($relation, $name, $constraints);

            // The key used to match the aggregated values with the parent documents must be read.
            $parentKey = $this->getAggregateParentKey($relation);

View on GitHub (pinned to 0634653039)