Automattic/mongoose · error · MongooseError

Invalid addFields() argument. Must be an object

Error message

Invalid addFields() argument. Must be an object

What it means

This TypeError comes from utils.populate(), the normalizer that every Query.populate(), Document.populate(), and object-based populate definition passes through. After flattening the arguments into an options object, it requires obj.path to be either a string or an array of strings; anything else (number, object, null inside an array, symbol) throws synchronously. The message interpolates the typeof of the original path argument so you can see what type you actually passed.

Source

Thrown at lib/aggregate.js:208

 *     aggregate.addFields({
 *         newField: '$b.nested'
 *       , plusTen: { $add: ['$val', 10]}
 *       , sub: {
 *            name: '$a'
 *         }
 *     })
 *
 *     // etc
 *     aggregate.addFields({ salary_k: { $divide: [ "$salary", 1000 ] } });
 *
 * @param {object} arg field specification
 * @see $addFields https://www.mongodb.com/docs/manual/reference/operator/aggregation/addFields/
 * @return {Aggregate}
 * @api public
 */
Aggregate.prototype.addFields = function(arg) {
  if (typeof arg !== 'object' || arg === null || Array.isArray(arg)) {
    throw new MongooseError('Invalid addFields() argument. Must be an object');
  }
  return this.append({ $addFields: Object.assign({}, arg) });
};

/**
 * Appends a new $project operator to this aggregate pipeline.
 *
 * Mongoose query [selection syntax](https://mongoosejs.com/docs/api/query.html#Query.prototype.select()) is also supported.
 *
 * #### Example:
 *
 *     // include a, include b, exclude _id
 *     aggregate.project("a b -_id");
 *
 *     // or you may use object notation, useful when
 *     // you have keys already prefixed with a "-"
 *     aggregate.project({a: 1, b: 1, _id: 0});
 *

View on GitHub (pinned to 49cdab0136)

Solutions

  1. Pass the path as a string: .populate('author') or as an object with a string path: .populate({ path: 'author', select: 'name' }).
  2. If passing an array, ensure every element is a string path or a valid populate object: .populate([{ path: 'author' }, { path: 'comments' }]).
  3. Check the variable you are interpolating — a typeof "undefined" in the message means the path variable was never set.
  4. Validate externally supplied populate specs before handing them to Mongoose.

Example fix

// before
const path = req.query.expand; // may be undefined or an object
const docs = await Model.find().populate(path);

// after
const expand = req.query.expand;
const pop = typeof expand === 'string' ? expand : Array.isArray(expand) && expand.every(p => typeof p === 'string') ? expand : [];
const docs = await Model.find().populate(pop);
Defensive patterns

Strategy: type-guard

Validate before calling

function normalizePopulate(path) {
  if (typeof path === 'string') return path;
  if (Array.isArray(path) && path.every(p => typeof p === 'string')) return path;
  if (Array.isArray(path) && path.every(p => p && typeof p === 'object' && typeof p.path === 'string')) return path;
  if (path && typeof path === 'object' && typeof path.path === 'string') return path;
  return undefined; // skip populate instead of throwing
}

Type guard

const isPopulatePath = (p) =>
  typeof p === 'string' ||
  (Array.isArray(p) && p.every(el => typeof el === 'string'));

Prevention

When it happens

Trigger: Calling .populate(42), .populate({ path: { nested: true } }), .populate(['user', 123]), or .populate({ path: ['a', null] }); passing a variable that was expected to be a path string but is an options object, e.g. .populate({ match: { x: 1 } }) with no path; template-built paths where the variable is undefined (typeof "undefined").

Common situations: Mixing up the two populate signatures (string path vs object spec); passing an array of populate objects where a string element is required; refactoring populate configs into variables and losing the path key; receiving populate specs from an API/JSON payload where a path is missing or numeric.

Related errors


AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21). Data as JSON: /api/errors/33085ad44f680922. Report an issue: GitHub.