Automattic/mongoose · error · MongooseError
Cannot mix array and object updates (current: ${_previewUpda
Error message
Cannot mix array and object updates (current: ${_previewUpdate(this[queryUpdateSymbol])}, incoming: ${_previewUpdate(update[queryUpdateSymbol])}) What it means
Thrown by Query.prototype._mergeUpdate when the query's stored update is an array (a pipeline update) but you merge in a Query object whose own update is a plain object. Mongoose cannot concatenate a pipeline stage list with an operator object like {$set: ...}, so it fails fast with a preview of both values instead of producing a corrupt update.
Source
Thrown at lib/query.js:4128
Query.prototype._mergeUpdate = function(update) {
_cloneUpdateIfShared(this);
const updatePipeline = this._mongooseOptions.updatePipeline;
if (!updatePipeline && Array.isArray(update)) {
throw new MongooseError('Cannot pass an array to query updates unless the `updatePipeline` option is set.');
}
if (!this[queryUpdateSymbol]) {
this[queryUpdateSymbol] = Array.isArray(update) ? [] : {};
}
if (update == null || (typeof update === 'object' && utils.hasOwnKeys(update) === false)) {
return;
}
if (update instanceof Query) {
if (Array.isArray(this[queryUpdateSymbol])) {
throw new MongooseError(`Cannot mix array and object updates (current: ${_previewUpdate(this[queryUpdateSymbol])}, incoming: ${_previewUpdate(update[queryUpdateSymbol])})`);
}
if (update[queryUpdateSymbol]) {
utils.mergeClone(this[queryUpdateSymbol], update[queryUpdateSymbol]);
}
} else if (Array.isArray(update)) {
if (!Array.isArray(this[queryUpdateSymbol])) {
// `_update` may be empty object by default, like in `doc.updateOne()`
// because we create the query first, then run hooks, then apply the update.
if (this[queryUpdateSymbol] == null || utils.isEmptyObject(this[queryUpdateSymbol])) {
this[queryUpdateSymbol] = [];
} else {
throw new MongooseError(`Cannot mix array and object updates (current: ${_previewUpdate(this[queryUpdateSymbol])}, incoming: ${_previewUpdate(update)})`);
}
}
this[queryUpdateSymbol] = this[queryUpdateSymbol].concat(update);
} else {
if (Array.isArray(this[queryUpdateSymbol])) {
throw new MongooseError(`Cannot mix array and object updates (current: ${_previewUpdate(this[queryUpdateSymbol])}, incoming: ${_previewUpdate(update)})`);View on GitHub (pinned to 49cdab0136)
Solutions
- Pick one update shape per query: convert the object update to an equivalent pipeline ([{$set: {...}}] with `updatePipeline: true`) or keep both as plain objects.
- Do not merge Query objects with different update kinds; execute them as separate updateOne/updateMany statements.
- Build a fresh Query per update instead of re-using and merging into one instance.
Example fix
// before
const q = Model.updateOne({}, [{ $set: { a: 1 } }], { updatePipeline: true });
const q2 = Model.updateOne({}, { $set: { b: 2 } });
q.updateOne({}, q2); // throws: Cannot mix array and object updates
// after
await Model.updateOne({}, [{ $set: { a: 1 } }], { updatePipeline: true });
await Model.updateOne({}, { $set: { b: 2 } }); Defensive patterns
Strategy: validation
Validate before calling
function assertSameUpdateKind(query, incoming) {
const currentIsArray = Array.isArray(query.getUpdate());
const incomingIsArray = incoming instanceof mongoose.Query ? Array.isArray(incoming.getUpdate()) : Array.isArray(incoming);
if (currentIsArray !== incomingIsArray) {
throw new Error('Refusing to merge array and object updates onto one query');
}
} Type guard
const updatesAreCompatible = (a, b) => Array.isArray(a) === Array.isArray(b);
Try / catch
try { q.updateOne({}, incoming); } catch (err) { if (err instanceof mongoose.Error && /Cannot mix array and object updates/.test(err.message)) { /* run as separate statements instead */ } throw err; } Prevention
- Never merge two Query objects with different update formats.
- Run mixed-format updates as separate updateOne calls.
- Keep query builders single-format.
When it happens
Trigger: `const q = Model.updateOne({}, [{$set: {a: 1}}], { updatePipeline: true }); q.updateOne({}, q2)` where q2 is a Query built with an object update, or any code path that calls query.merge(otherQuery) with mismatched update shapes.
Common situations: Helper functions that accept either an update object or a Query and chain them onto one builder query; refactoring a query builder so some branches use pipeline updates and others use operator objects; test fixtures that reuse and merge Query objects.
Related errors
- Cannot mix array and object updates (current: ${_previewUpda
- Invalid addFields() argument. Must be an object
- Invalid select() argument. Must be string or object.
- Options must be an object, got "${options}"
- sort() takes at most 2 arguments
AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21).
Data as JSON: /api/errors/0e17150506a61930.
Report an issue: GitHub.