mongodb/laravel-mongodb · error · InvalidArgumentException

The aggregate column name

Error message

The aggregate column name "%s" must not start with "$".

What it means

withAggregate() rejects column names beginning with '$' because such names collide with MongoDB aggregation operator syntax and are almost always a mistake (e.g. passing '$sum' as a column instead of a function). Throws InvalidArgumentException naming the offending column.

Solutions

  1. Remove the leading '$' from the column name: use 'total', not '$total'
  2. Move aggregation operators to the function argument position (e.g. 'sum'), not the column
  3. Do not attempt raw pipeline expressions here — use raw aggregation via the MongoDB collection if needed
  4. Sanitize dynamic column inputs by ltrim($column, '$')

Example fix

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

Strategy: validation

Validate before calling

if (str_starts_with($column, '$')) {
    $column = ltrim($column, '$');
}

Type guard

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

Try / catch

try {
    $query->withAggregate('orders', 'sum', $column);
} catch (InvalidArgumentException $e) {
    if (str_contains($e->getMessage(), 'must not start with')) {
        $column = ltrim($column, '$');
        $query->withAggregate('orders', 'sum', $column);
    } else {
        throw $e;
    }
}

Prevention

When it happens

Trigger: Passing a column like '$total' or an aggregation operator ('$$ROOT', '$sum') as the column argument of withAggregate(), often after confusing the function and column parameters or copying raw pipeline syntax.

Common situations: Users translating a raw MongoDB aggregation pipeline into the query builder; variables holding operator names from previous pipeline code; accidental double '$' from string interpolation.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


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

Appendix: source

Thrown at src/Helpers/QueriesRelationshipAggregates.php:74

    {
        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);
            if ($parentKey !== null && $this->getQuery()->columns !== null) {
                $this->addSelect($parentKey);
            }

View on GitHub (pinned to 0634653039)