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
- Remove the leading '$' from the column name: use 'total', not '$total'
- Move aggregation operators to the function argument position (e.g. 'sum'), not the column
- Do not attempt raw pipeline expressions here — use raw aggregation via the MongoDB collection if needed
- 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
- Never copy raw pipeline field paths ('$field') into query-builder column args
- Remember the second argument of withAggregate is the function ('sum'), not an operator
- Sanitize dynamic column input with ltrim($col, '$') when sourced from pipeline code
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
- Aggregate function " " is not supported by MongoDB…
- The aggregate column name must be a string.
- Method ::initializeModelAttributes() requires Laravel 13 or…
- Constant ::SCHEMA_VERSION is required when using…
- Constraints on the embedded relation
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)