mongodb/node-mongodb-native · error · MongoAPIError
ChangeStream cannot be used as an EventEmitter after being…
Error message
ChangeStream cannot be used as an EventEmitter after being used as an iterator
What it means
Thrown when a 'change' event listener is added to a ChangeStream that has already been used as an async iterator (via next(), hasNext(), tryNext(), or for-await-of). The ChangeStream enforces a single mode: either EventEmitter-style (event listeners) or iterator-style (async iteration). Switching from iterator to emitter is forbidden. This is a MongoAPIError.
Solutions
- Choose one consumption pattern (events or iterator) per ChangeStream instance and stick with it
- If you need to switch patterns, close the current change stream and create a new one with the same options/resume token
- Use the resume token from the closed stream to start the new one at the correct position
Example fix
// before
const doc = await changeStream.next(); // sets iterator mode
changeStream.on('change', handler); // throws
// after
const token = changeStream.resumeToken;
await changeStream.close();
const newStream = collection.watch(pipeline, { resumeAfter: token });
newStream.on('change', handler); Defensive patterns
Strategy: validation
Validate before calling
// Decide on one consumption mode before using the change stream
// Option A: events only
changeStream.on('change', handler);
// Option B: iterator only
for await (const change of changeStream) { ... }
// Do NOT mix the two on the same instance. Try / catch
try {
changeStream.on('change', handler);
} catch (error) {
if (error instanceof MongoAPIError && error.message.includes('EventEmitter')) {
// Stream was used as iterator; create a new stream for event mode
const token = changeStream.resumeToken;
const newStream = collection.watch(pipeline, { resumeAfter: token });
newStream.on('change', handler);
}
} Prevention
- Choose one consumption pattern (events or iterator) per ChangeStream instance at design time
- Document the chosen pattern in code comments to prevent other developers from mixing modes
- If you need both patterns, use separate ChangeStream instances
When it happens
Trigger: First calling changeStream.next() or using for-await-of, then later calling changeStream.on('change', callback). The mode is set to 'iterator' by the first iterator-style call and cannot revert to 'emitter'.
Common situations: Refactoring code from for-await-of to event-based listening without creating a new change stream; mixing two consumer patterns in the same module; shared change stream instance used by both an iterator consumer and an event consumer.
Related errors
- ChangeStream cannot be used as an iterator after being used…
- 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/c34e53ff26c44563.
Report an issue: GitHub.
Appendix: source
Thrown at src/change_stream.ts:880
*
* NOTE: When using a Stream to process change stream events, the stream will
* NOT automatically resume in the case a resumable error is encountered.
*
* @throws MongoChangeStreamError if the underlying cursor or the change stream is closed
*/
stream(): Readable & AsyncIterable<TChange> {
if (this.closed) {
throw new MongoChangeStreamError(CHANGESTREAM_CLOSED_ERROR);
}
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';
}
/**View on GitHub (pinned to dce7939f86)