Automattic/mongoose · error · MongooseError
AggregationCursor.prototype.next() no longer accepts a callb
Error message
AggregationCursor.prototype.next() no longer accepts a callback
What it means
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.
Source
Thrown at lib/cursor/aggregationCursor.js:293
})
.catch(error => {
callback(error);
});
return this;
};
/**
* Get the next document from this cursor. Will return `null` when there are
* no documents left.
*
* @return {Promise}
* @api public
* @method next
*/
AggregationCursor.prototype.next = async function next() {
if (typeof arguments[0] === 'function') {
throw new MongooseError('AggregationCursor.prototype.next() no longer accepts a callback');
}
const _this = this;
const model = this.agg._model;
return cursorNextChannel.trace(function maybeTracedAggCursorNext() {
return new Promise((resolve, reject) => {
_next(_this, (err, res) => {
if (err != null) {
return reject(err);
}
resolve(res);
});
});
}, () => ({
operation: 'aggregate',
collection: model?.collection?.name,
database: model?.db?.name,
serverAddress: model?.db?.host,
serverPort: model?.db?.port,View on GitHub (pinned to 49cdab0136)
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
Example fix
// before
aggCursor.next(function (err, doc) {
if (err) throw err;
if (!doc) return done();
handle(doc);
});
// after
let doc;
while ((doc = await aggCursor.next()) !== null) {
handle(doc);
} Defensive patterns
Strategy: validation
Validate before calling
function nextDoc(cursor, ...args) {
if (args.some(a => typeof a === 'function')) {
throw new TypeError('next() takes no callback; await the returned promise');
}
return cursor.next();
} Prevention
- 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
When it happens
Trigger: aggCursor.next((err, doc) => {...}) — any function passed as the first argument to next().
Common situations: Legacy iteration loops left unmigrated during a Mongoose 6 to 7+ upgrade; old tutorials and Stack Overflow snippets using callback-style cursors.
Related errors
- AggregationCursor.prototype.close() no longer accepts a call
- AggregationCursor.prototype.eachAsync() no longer accepts a
- QueryCursor.prototype.close() no longer accepts a callback
- QueryCursor.prototype.next() no longer accepts a callback
- QueryCursor.prototype.eachAsync() no longer accepts a callba
AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21).
Data as JSON: /api/errors/380c30dbafccd584.
Report an issue: GitHub.