{"record":{"id":"db65563229a7eb5e","repo":"mongodb/laravel-mongodb","slug":"the-aggregate-column-name-s-must-not-start-with","errorCode":null,"errorMessage":"The aggregate column name \"%s\" must not start with \"$\".","messagePattern":"The aggregate column name \"(.+?)\" must not start with \"\\$\"\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/Helpers/QueriesRelationshipAggregates.php","lineNumber":74,"sourceCode":"    {\n        if (empty($relations)) {\n            return $this;\n        }\n\n        if (! in_array($function, self::AGGREGATE_FUNCTIONS, true)) {\n            throw new InvalidArgumentException(sprintf(\n                'Aggregate function \"%s\" is not supported by MongoDB. Supported functions are: %s.',\n                $function ?? 'null',\n                implode(', ', self::AGGREGATE_FUNCTIONS),\n            ));\n        }\n\n        if (! is_string($column)) {\n            throw new InvalidArgumentException('The aggregate column name must be a string.');\n        }\n\n        if (str_starts_with($column, '$')) {\n            throw new InvalidArgumentException(sprintf(\n                'The aggregate column name \"%s\" must not start with \"$\".',\n                $column,\n            ));\n        }\n\n        foreach ($this->parseWithRelations(is_array($relations) ? $relations : [$relations]) as $name => $constraints) {\n            [$name, $alias] = $this->resolveAggregateAlias($name, $function, $column);\n\n            $relation = $this->getRelationWithoutConstraints($name);\n            $this->assertAggregateRelationSupported($relation, $name);\n            $this->assertEmbeddedConstraintsSupported($relation, $name, $constraints);\n\n            // The key used to match the aggregated values with the parent documents must be read.\n            $parentKey = $this->getAggregateParentKey($relation);\n            if ($parentKey !== null && $this->getQuery()->columns !== null) {\n                $this->addSelect($parentKey);\n            }\n","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/mongodb/laravel-mongodb/blob/0634653039468ceb0268a69192bdac64469ed043/src/Helpers/QueriesRelationshipAggregates.php#L56-L92","documentation":"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.","triggerScenarios":"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.","commonSituations":"Users translating a raw MongoDB aggregation pipeline into the query builder; variables holding operator names from previous pipeline code; accidental double '$' from string interpolation.","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, '$')"],"exampleFix":"// before\n$query->withAggregate('orders', 'sum', '$total');\n// after\n$query->withAggregate('orders', 'sum', 'total');","handlingStrategy":"validation","validationCode":"if (str_starts_with($column, '$')) {\n    $column = ltrim($column, '$');\n}","typeGuard":"function isValidAggregateColumn(mixed $column): bool {\n    return is_string($column) && $column !== '' && !str_starts_with($column, '$');\n}","tryCatchPattern":"try {\n    $query->withAggregate('orders', 'sum', $column);\n} catch (InvalidArgumentException $e) {\n    if (str_contains($e->getMessage(), 'must not start with')) {\n        $column = ltrim($column, '$');\n        $query->withAggregate('orders', 'sum', $column);\n    } else {\n        throw $e;\n    }\n}","preventionTips":["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"],"tags":["eloquent","aggregates","naming"],"backgroundTag":"invalid-identifier-format","analyzedSha":"0634653039468ceb0268a69192bdac64469ed043","analyzedAt":"2026-09-15T02:56:37.067Z","contentChangedAt":"2026-09-15T02:56:37.067Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}