mongodb/node-mongodb-native · error · MongoInvalidArgumentError

Argument "pipeline" must be an array of aggregation stages

Error message

Argument "pipeline" must be an array of aggregation stages

What it means

Thrown by Collection.aggregate when the pipeline argument is not an array. The method's contract requires Document[] (an array of stage objects); a non-array is a programming error and raises a MongoInvalidArgumentError synchronously before constructing the AggregationCursor.

Solutions

  1. Wrap stages in an array: aggregate([{ $match: {} }]).
  2. Default the parameter: aggregate(pipeline ?? []).
  3. Guard dynamic pipelines with Array.isArray.
  4. Type the variable as Document[] so TS enforces it.

Example fix

// before
collection.aggregate({ $match: { status: 'active' } });

// after
collection.aggregate([{ $match: { status: 'active' } }]);
Defensive patterns

Strategy: validation

Validate before calling

const stages = Array.isArray(pipeline) ? pipeline : [pipeline];
collection.aggregate(stages);

Type guard

function isStageArray(v: unknown): v is Record<string, unknown>[] {
  return Array.isArray(v) && v.every(s => s != null && typeof s === 'object' && !Array.isArray(s));
}

Prevention

When it happens

Trigger: Fires at src/collection.ts:1063 when `!Array.isArray(pipeline)`. Occurs when a caller passes a single stage object, undefined, a string, or any non-array to aggregate.

Common situations: Passing {$match:{}} instead of [{$match:{}}]; passing undefined because pipeline was optional and never defaulted; building stages conditionally and forgetting to wrap; spreading a stage instead of an array.

Related errors


AI-assisted analysis of mongodb/node-mongodb-native@dce7939f86 (2026-08-11). Data as JSON: /api/errors/3c9b0f0bbb65d974. Report an issue: GitHub.

Appendix: source

Thrown at src/collection.ts:1063

        filter,
        update,
        resolveOptions(this, options)
      ) as TODO_NODE_3286
    );
  }

  /**
   * Execute an aggregation framework pipeline against the collection, needs MongoDB \>= 2.2
   *
   * @param pipeline - An array of aggregation pipelines to execute
   * @param options - Optional settings for the command
   */
  aggregate<T extends Document = Document>(
    pipeline: Document[] = [],
    options?: AggregateOptions & Abortable
  ): AggregationCursor<T> {
    if (!Array.isArray(pipeline)) {
      throw new MongoInvalidArgumentError(
        'Argument "pipeline" must be an array of aggregation stages'
      );
    }

    return new AggregationCursor(
      this.client,
      this.s.namespace,
      pipeline,
      resolveOptions(this, options)
    );
  }

  /**
   * Create a new Change Stream, watching for new changes (insertions, updates, replacements, deletions, and invalidations) in this collection.
   *
   * @remarks
   * watch() accepts two generic arguments for distinct use cases:
   * - The first is to override the schema that may be defined for this specific collection

View on GitHub (pinned to dce7939f86)