mongodb/laravel-mongodb · error · BadMethodCallException

Aggregation builder does not support previous query-builder…

Error message

Aggregation builder does not support previous query-builder instructions. Use a $match stage instead.

What it means

The fluent AggregationBuilder starts from a clean pipeline; existing query-builder where clauses cannot be converted automatically. If ->where() etc. were applied before calling ->aggregate() with no function, this BadMethodCallException is thrown, directing you to use a $match stage.

Solutions

  1. Move each ->where(...) condition into a ->match(...) stage on the AggregationBuilder.
  2. Call aggregate(null) on a fresh, unfiltered Builder instance.
  3. If you want where-clauses translated for you, use aggregateRaw()/group aggregations instead of the fluent builder.

Example fix

// before
Model::where('status', 'active')->aggregate(null);
// after
Model::aggregate(null)->match('status', 'active');
Defensive patterns

Strategy: validation

Validate before calling

if (! empty($query->getQuery()->wheres)) {
    // convert wheres to a $match stage before the fluent builder call
}
$agg = $fresh = Model::query()->aggregate(null);

Type guard

function hasQueryBuilderState(Illuminate\Database\Eloquent\Builder $q): bool { return ! empty($q->getQuery()->wheres); }

Try / catch

try {
    $agg = $query->aggregate(null);
} catch (BadMethodCallException $e) {
    if (str_contains($e->getMessage(), '$match stage')) {
        $agg = $query->getModel()->query()->aggregate(null)->match('status', 'active');
    } else { throw $e; }
}

Prevention

When it happens

Trigger: Chaining like Model::where('status','active')->aggregate(null) — wheres are non-empty when the fluent builder path runs.

Common situations: Developers reusing an existing filtered query object and switching to the aggregation builder, expecting filters to be preserved.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at src/Query/Builder.php:586

    /** @return ($function is null ? AggregationBuilder : mixed) */
    #[Override]
    public function aggregate($function = null, $columns = ['*'])
    {
        assert(is_array($columns), new TypeError(sprintf('Argument #2 ($columns) must be of type array, %s given', get_debug_type($columns))));

        if ($function === null) {
            if (! trait_exists(FluentFactoryTrait::class)) {
                // This error will be unreachable when the mongodb/builder package will be merged into mongodb/mongodb
                throw new BadMethodCallException('Aggregation builder requires package mongodb/builder 0.2+');
            }

            if ($columns !== ['*']) {
                throw new InvalidArgumentException('Columns cannot be specified to create an aggregation builder. Add a $project stage instead.');
            }

            if ($this->wheres) {
                throw new BadMethodCallException('Aggregation builder does not support previous query-builder instructions. Use a $match stage instead.');
            }

            return new AggregationBuilder($this->collection, $this->options);
        }

        $this->aggregate = [
            'function' => $function,
            'columns' => $columns,
        ];

        $previousColumns = $this->columns;

        // We will also back up the select bindings since the select clause will be
        // removed when performing the aggregate function. Once the query is run
        // we will add the bindings back onto this query so they can get used.
        $previousSelectBindings = $this->bindings['select'];

        $this->bindings['select'] = [];

View on GitHub (pinned to 0634653039)