Automattic/mongoose · warning · MongooseError
Aggregate pipeline for $unionWith cannot include `$out` or `
Error message
Aggregate pipeline for $unionWith cannot include `$out` or `$merge` stages
What it means
The { returnOriginal: true|false } option on findOneAndUpdate()/findOneAndReplace() is the older sibling of { new }: returnOriginal:true returned the pre-update document, false the post-update one. convertNewToReturnDocument() warns and maps returnOriginal:true -> returnDocument:'before', false -> 'after', then removes the key. Internally Mongoose also re-derives returnOriginal for old driver versions, but user code should speak returnDocument only.
Source
Thrown at lib/aggregate.js:1047
};
/**
* Returns the current pipeline as a `$unionWith`-safe pipeline.
* Throws if this pipeline contains `$out` or `$merge`.
*
* #### Example:
*
* const base = MyModel.aggregate().match({ test: 1 });
* base.pipelineForUnionWith(); // [{ $match: { test: 1 } }]
*
* @return {PipelineStage[]} The current pipeline with `$unionWith` stage restrictions
* @api public
*/
Aggregate.prototype.pipelineForUnionWith = function pipelineForUnionWith() {
for (const stage of this._pipeline) {
if (stage?.$out != null || stage?.$merge != null) {
throw new MongooseError('Aggregate pipeline for $unionWith cannot include `$out` or `$merge` stages');
}
}
return this._pipeline;
};
/**
* Executes the aggregate pipeline on the currently bound Model.
*
* #### Example:
* const result = await aggregate.exec();
*
* @return {Promise}
* @api public
*/
Aggregate.prototype.exec = async function exec() {
if (!this._model && !this._connection) {View on GitHub (pinned to 49cdab0136)
Solutions
- Replace with returnDocument: { returnOriginal: false } -> { returnDocument: 'after' }; { returnOriginal: true } -> { returnDocument: 'before' }.
- Update shared query wrappers/DAOs so callers cannot pass returnOriginal anymore.
- Grep for 'returnOriginal' repo-wide to catch both the global set() form and per-query options in one pass.
Example fix
// before
const doc = await Model.findOneAndUpdate(filter, update, { returnOriginal: false });
// after
const doc = await Model.findOneAndUpdate(filter, update, { returnDocument: 'after' }); Defensive patterns
Strategy: validation
Validate before calling
function normalizeUpdateOptions(opts = {}) {
const { new: _n, returnOriginal, ...rest } = opts;
if (returnOriginal !== undefined) rest.returnDocument = returnOriginal ? 'before' : 'after';
return rest;
} Prevention
- Use returnDocument exclusively in repository/DAO layers.
- Sanitize options passed through from older callers with a normalize step.
- Grep for 'returnOriginal' (both global set and per-query) during Mongoose upgrades.
When it happens
Trigger: Model.findOneAndUpdate(filter, update, { returnOriginal: false }); configs or helpers that forwarded the mongoose.set('returnOriginal') value down into per-query options; findOneAndReplace calls copied from Mongoose 5-era code.
Common situations: Same migration wave as the removed global option — old query helpers, repository-layer wrappers, and DAOs that accept an options object and pass it through; mixed codebases where some paths used new and others returnOriginal.
Related errors
- Aggregate has empty pipeline
- Aggregate.prototype.explain() no longer accepts a callback
- Aggregate `near()` argument must have a `near` property
- Aggregate `near()` argument has invalid coordinates, got "${
- Provided object has both field "${name}" and its alias "${al
AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21).
Data as JSON: /api/errors/5749ec4428bb193a.
Report an issue: GitHub.