mongodb/node-mongodb-native · error · MongoAPIError
ChangeStream cannot be used as an iterator after being used…
Error message
ChangeStream cannot be used as an iterator after being used as an EventEmitter
What it means
Thrown when an iterator-style method (next(), hasNext(), tryNext(), or for-await-of) is called on a ChangeStream that has already been used as an EventEmitter (a 'change' listener was attached). The ChangeStream enforces a single consumption mode and switching from emitter to iterator is forbidden. This is a MongoAPIError.
Solutions
- Choose one consumption pattern per ChangeStream instance from the start
- If you must switch, create a new change stream using the resume token from the previous one
- Remove all 'change' listeners and close the stream before creating a new iterator-based stream
Example fix
// before
changeStream.on('change', handler); // sets emitter mode
const doc = await changeStream.next(); // throws
// after
const token = changeStream.resumeToken;
await changeStream.close();
const newStream = collection.watch(pipeline, { resumeAfter: token });
for await (const change of newStream) {
handler(change);
} Defensive patterns
Strategy: validation
Validate before calling
// Decide on one consumption mode before using the change stream
// If events are attached, do not call iterator methods
if (changeStream.listenerCount('change') > 0) {
throw new Error('Cannot use iterator methods after attaching change listeners');
}
const doc = await changeStream.next(); Try / catch
try {
const doc = await changeStream.next();
} catch (error) {
if (error instanceof MongoAPIError && error.message.includes('iterator')) {
// Stream is in emitter mode; create new stream for iteration
const token = changeStream.resumeToken;
const newStream = collection.watch(pipeline, { resumeAfter: token });
doc = await newStream.next();
}
} Prevention
- Choose one consumption pattern per ChangeStream instance from the start
- If switching from events to iteration, close and recreate the stream with a resume token
- Avoid sharing change stream instances across modules that use different consumption patterns
When it happens
Trigger: First calling changeStream.on('change', callback) (which sets emitter mode via _setIsEmitter), then later calling changeStream.next() or using for-await-of on the same instance.
Common situations: Refactoring from event listeners to async iteration without recreating the stream; shared change stream instances across modules where one attaches events and another iterates; code that attaches a temporary listener then tries to iterate.
Related errors
- ChangeStream cannot be used as an EventEmitter after being…
- Parent provided to ChangeStream constructor must be an…
- A change stream document has been received that lacks a…
- Argument "docs" must be an array of documents
- Argument "operations" must be an array of documents
AI-assisted analysis of mongodb/node-mongodb-native@dce7939f86 (2026-08-11).
Data as JSON: /api/errors/32ea2ad934675f1c.
Report an issue: GitHub.
Appendix: source
Thrown at src/change_stream.ts:891
return this.cursor.stream();
}
/** @internal */
private _setIsEmitter(): void {
if (this.mode === 'iterator') {
// TODO(NODE-3485): Replace with MongoChangeStreamModeError
throw new MongoAPIError(
'ChangeStream cannot be used as an EventEmitter after being used as an iterator'
);
}
this.mode = 'emitter';
}
/** @internal */
private _setIsIterator(): void {
if (this.mode === 'emitter') {
// TODO(NODE-3485): Replace with MongoChangeStreamModeError
throw new MongoAPIError(
'ChangeStream cannot be used as an iterator after being used as an EventEmitter'
);
}
this.mode = 'iterator';
}
/**
* Create a new change stream cursor based on self's configuration
* @internal
*/
private _createChangeStreamCursor(
options: ChangeStreamOptions | ChangeStreamCursorOptions
): ChangeStreamCursor<TSchema, TChange> {
const changeStreamStageOptions: Document = filterOutOptions(options);
if (this.type === CHANGE_DOMAIN_TYPES.CLUSTER) {
changeStreamStageOptions.allChangesForCluster = true;
}
const pipeline = [{ $changeStream: changeStreamStageOptions }, ...this.pipeline];View on GitHub (pinned to dce7939f86)