{"record":{"id":"380c30dbafccd584","repo":"Automattic/mongoose","slug":"aggregationcursor-prototype-next-no-longer-accep","errorCode":null,"errorMessage":"AggregationCursor.prototype.next() no longer accepts a callback","messagePattern":"AggregationCursor\\.prototype\\.next\\(\\) no longer accepts a callback","errorType":"exception","errorClass":"MongooseError","httpStatus":null,"severity":"error","filePath":"lib/cursor/aggregationCursor.js","lineNumber":293,"sourceCode":"    })\n    .catch(error => {\n      callback(error);\n    });\n  return this;\n};\n\n/**\n * Get the next document from this cursor. Will return `null` when there are\n * no documents left.\n *\n * @return {Promise}\n * @api public\n * @method next\n */\n\nAggregationCursor.prototype.next = async function next() {\n  if (typeof arguments[0] === 'function') {\n    throw new MongooseError('AggregationCursor.prototype.next() no longer accepts a callback');\n  }\n  const _this = this;\n  const model = this.agg._model;\n  return cursorNextChannel.trace(function maybeTracedAggCursorNext() {\n    return new Promise((resolve, reject) => {\n      _next(_this, (err, res) => {\n        if (err != null) {\n          return reject(err);\n        }\n        resolve(res);\n      });\n    });\n  }, () => ({\n    operation: 'aggregate',\n    collection: model?.collection?.name,\n    database: model?.db?.name,\n    serverAddress: model?.db?.host,\n    serverPort: model?.db?.port,","sourceCodeStart":275,"sourceCodeEnd":311,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/cursor/aggregationCursor.js#L275-L311","documentation":"AggregationCursor#next() became promise-based when Mongoose 7 dropped callbacks. Calling it with a function as the first argument throws immediately; next() now resolves with the next document or null when the cursor is exhausted.","triggerScenarios":"aggCursor.next((err, doc) => {...}) — any function passed as the first argument to next().","commonSituations":"Legacy iteration loops left unmigrated during a Mongoose 6 to 7+ upgrade; old tutorials and Stack Overflow snippets using callback-style cursors.","solutions":["Use const doc = await cursor.next() and loop until it resolves null","Rewrite callback pagination as: while ((doc = await cursor.next()) !== null) {...}","For bulk processing prefer eachAsync(fn, { parallel }) over manual next() loops"],"exampleFix":"// before\naggCursor.next(function (err, doc) {\n  if (err) throw err;\n  if (!doc) return done();\n  handle(doc);\n});\n\n// after\nlet doc;\nwhile ((doc = await aggCursor.next()) !== null) {\n  handle(doc);\n}","handlingStrategy":"validation","validationCode":"function nextDoc(cursor, ...args) {\n  if (args.some(a => typeof a === 'function')) {\n    throw new TypeError('next() takes no callback; await the returned promise');\n  }\n  return cursor.next();\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Rewrite callback iteration loops as while ((doc = await cursor.next()) !== null)","Prefer eachAsync() for structured processing instead of hand-rolled next() loops","Add a lint/grep check for next( calls with function arguments during Mongoose 7 migrations"],"tags":["aggregation-cursor","callback","promise","mongoose-7","migration"],"backgroundTag":"callback-api-removed","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}