{"record":{"id":"0e17150506a61930","repo":"Automattic/mongoose","slug":"cannot-mix-array-and-object-updates-current-p","errorCode":null,"errorMessage":"Cannot mix array and object updates (current: ${_previewUpdate(this[queryUpdateSymbol])}, incoming: ${_previewUpdate(update[queryUpdateSymbol])})","messagePattern":"Cannot mix array and object updates \\(current: (.+?), incoming: (.+?)\\)","errorType":"exception","errorClass":"MongooseError","httpStatus":null,"severity":"error","filePath":"lib/query.js","lineNumber":4128,"sourceCode":"\nQuery.prototype._mergeUpdate = function(update) {\n  _cloneUpdateIfShared(this);\n\n  const updatePipeline = this._mongooseOptions.updatePipeline;\n  if (!updatePipeline && Array.isArray(update)) {\n    throw new MongooseError('Cannot pass an array to query updates unless the `updatePipeline` option is set.');\n  }\n  if (!this[queryUpdateSymbol]) {\n    this[queryUpdateSymbol] = Array.isArray(update) ? [] : {};\n  }\n\n  if (update == null || (typeof update === 'object' && utils.hasOwnKeys(update) === false)) {\n    return;\n  }\n\n  if (update instanceof Query) {\n    if (Array.isArray(this[queryUpdateSymbol])) {\n      throw new MongooseError(`Cannot mix array and object updates (current: ${_previewUpdate(this[queryUpdateSymbol])}, incoming: ${_previewUpdate(update[queryUpdateSymbol])})`);\n    }\n    if (update[queryUpdateSymbol]) {\n      utils.mergeClone(this[queryUpdateSymbol], update[queryUpdateSymbol]);\n    }\n  } else if (Array.isArray(update)) {\n    if (!Array.isArray(this[queryUpdateSymbol])) {\n      // `_update` may be empty object by default, like in `doc.updateOne()`\n      // because we create the query first, then run hooks, then apply the update.\n      if (this[queryUpdateSymbol] == null || utils.isEmptyObject(this[queryUpdateSymbol])) {\n        this[queryUpdateSymbol] = [];\n      } else {\n        throw new MongooseError(`Cannot mix array and object updates (current: ${_previewUpdate(this[queryUpdateSymbol])}, incoming: ${_previewUpdate(update)})`);\n      }\n    }\n    this[queryUpdateSymbol] = this[queryUpdateSymbol].concat(update);\n  } else {\n    if (Array.isArray(this[queryUpdateSymbol])) {\n      throw new MongooseError(`Cannot mix array and object updates (current: ${_previewUpdate(this[queryUpdateSymbol])}, incoming: ${_previewUpdate(update)})`);","sourceCodeStart":4110,"sourceCodeEnd":4146,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/query.js#L4110-L4146","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","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."],"exampleFix":"// before\nconst q = Model.updateOne({}, [{ $set: { a: 1 } }], { updatePipeline: true });\nconst q2 = Model.updateOne({}, { $set: { b: 2 } });\nq.updateOne({}, q2); // throws: Cannot mix array and object updates\n\n// after\nawait Model.updateOne({}, [{ $set: { a: 1 } }], { updatePipeline: true });\nawait Model.updateOne({}, { $set: { b: 2 } });","handlingStrategy":"validation","validationCode":"function assertSameUpdateKind(query, incoming) {\n  const currentIsArray = Array.isArray(query.getUpdate());\n  const incomingIsArray = incoming instanceof mongoose.Query ? Array.isArray(incoming.getUpdate()) : Array.isArray(incoming);\n  if (currentIsArray !== incomingIsArray) {\n    throw new Error('Refusing to merge array and object updates onto one query');\n  }\n}","typeGuard":"const updatesAreCompatible = (a, b) => Array.isArray(a) === Array.isArray(b);","tryCatchPattern":"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; }","preventionTips":["Never merge two Query objects with different update formats.","Run mixed-format updates as separate updateOne calls.","Keep query builders single-format."],"tags":["mongoose","query","update-pipeline","invalid-argument"],"backgroundTag":"mongoose-mixed-update-types","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}