{"id":"3c9b0f0bbb65d974","repo":"mongodb/node-mongodb-native","slug":"argument-pipeline-must-be-an-array-of-aggregatio","errorCode":null,"errorMessage":"Argument \"pipeline\" must be an array of aggregation stages","messagePattern":"Argument \"pipeline\" must be an array of aggregation stages","errorType":"exception","errorClass":"MongoInvalidArgumentError","httpStatus":null,"severity":"error","filePath":"src/collection.ts","lineNumber":1063,"sourceCode":"        filter,\n        update,\n        resolveOptions(this, options)\n      ) as TODO_NODE_3286\n    );\n  }\n\n  /**\n   * Execute an aggregation framework pipeline against the collection, needs MongoDB \\>= 2.2\n   *\n   * @param pipeline - An array of aggregation pipelines to execute\n   * @param options - Optional settings for the command\n   */\n  aggregate<T extends Document = Document>(\n    pipeline: Document[] = [],\n    options?: AggregateOptions & Abortable\n  ): AggregationCursor<T> {\n    if (!Array.isArray(pipeline)) {\n      throw new MongoInvalidArgumentError(\n        'Argument \"pipeline\" must be an array of aggregation stages'\n      );\n    }\n\n    return new AggregationCursor(\n      this.client,\n      this.s.namespace,\n      pipeline,\n      resolveOptions(this, options)\n    );\n  }\n\n  /**\n   * Create a new Change Stream, watching for new changes (insertions, updates, replacements, deletions, and invalidations) in this collection.\n   *\n   * @remarks\n   * watch() accepts two generic arguments for distinct use cases:\n   * - The first is to override the schema that may be defined for this specific collection","sourceCodeStart":1045,"sourceCodeEnd":1081,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/3366c21a6311e02f1be91da982f9b93d3cce99a0/src/collection.ts#L1045-L1081","documentation":"Thrown by Collection.aggregate() when the pipeline argument is not an Array. The aggregation framework requires an ordered array of stage objects (e.g. [{$match: ...}, {$group: ...}]). This MongoInvalidArgumentError is raised synchronously before the AggregationCursor is constructed; no server round-trip occurs.","triggerScenarios":"Passing a single stage object instead of an array; passing undefined (note pipeline defaults to [] but an explicit non-array still fails); passing a comma-separated string or an object keyed by stage names; passing a generator function instead of its result.","commonSituations":"Building a pipeline conditionally and ending up with undefined when no stages apply; copy-pasting a stage without wrapping in []; mis-typing a config object as { $match: {...} } rather than [{ $match: {...} }].","solutions":["Coerce to an array: collection.aggregate(Array.isArray(pipeline) ? pipeline : [pipeline]).","Default the local variable: const pipeline = rawPipeline ?? [];","Guard with Array.isArray and surface a caller-side error.","Type the builder's return as Document[] so TypeScript catches regressions."],"exampleFix":"// before\nconst stage = filter ? { $match: filter } : null;\nawait collection.aggregate(stage).toArray();\n// after\nconst pipeline = [];\nif (filter) pipeline.push({ $match: filter });\nawait collection.aggregate(pipeline).toArray();","handlingStrategy":"type-guard","validationCode":"function asPipeline(stages: unknown): Record<string, unknown>[] {\n  if (stages == null) return [];\n  if (!Array.isArray(stages)) return [stages as Record<string, unknown>];\n  return stages as Record<string, unknown>[];\n}\nawait collection.aggregate(asPipeline(raw)).toArray();","typeGuard":"const isPipeline = (v: unknown): v is Record<string, unknown>[] =>\n  Array.isArray(v) && v.every(s => s != null && typeof s === 'object' && !Array.isArray(s));","tryCatchPattern":"try {\n  await collection.aggregate(pipeline).toArray();\n} catch (e) {\n  if (e instanceof MongoInvalidArgumentError && /pipeline.*must be an array/.test(e.message)) {\n    throw new TypeError('Aggregation pipeline must be an array of stages');\n  }\n  throw e;\n}","preventionTips":["Default pipeline variables to [].","Type pipeline builders as Document[][].","Wrap single stages in [] rather than passing them bare."],"tags":["validation","typescript","aggregation","crud"],"analyzedSha":"3366c21a6311e02f1be91da982f9b93d3cce99a0","analyzedAt":"2026-08-04T13:40:15.335Z","schemaVersion":2}