Automattic/mongoose · error · Error

Mongoose does not support calling populate() on nested docs.

Error message

Mongoose does not support calling populate() on nested docs. Instead of `doc.arr[0].populate("path")`, use `doc.populate("arr.0.path")`

What it means

ArraySubdocument.prototype.populate() is deliberately unimplemented and always throws. Populating from inside an array element would need the parent's populate context, so Mongoose requires you to call populate on the root document with the dotted path including the array index.

Source

Thrown at lib/types/arraySubdocument.js:89

 */

ArraySubdocument.prototype.$setIndex = function(index) {
  this.__index = index;

  if (this.$__?.validationError != null) {
    const keys = Object.keys(this.$__.validationError.errors);
    for (const key of keys) {
      this.invalidate(key, this.$__.validationError.errors[key]);
    }
  }
};

/*!
 * ignore
 */

ArraySubdocument.prototype.populate = function() {
  throw new Error('Mongoose does not support calling populate() on nested ' +
    'docs. Instead of `doc.arr[0].populate("path")`, use ' +
    '`doc.populate("arr.0.path")`');
};

/*!
 * ignore
 */

ArraySubdocument.prototype.$__removeFromParent = function() {
  const _id = this._doc._id;
  if (!_id) {
    throw new Error('For your own good, Mongoose does not know ' +
      'how to remove an ArraySubdocument that has no _id');
  }
  this.__parentArray.pull({ _id: _id });
};

/**

View on GitHub (pinned to 49cdab0136)

Solutions

  1. Call populate on the root document with the indexed dotted path: doc.populate('arr.0.user')
  2. For multiple elements use the parent path (doc.populate('arr.user')) — Mongoose populates every element
  3. Await the result: await doc.populate('arr.0.user')

Example fix

// before
doc.items[0].populate('product');
// after
await doc.populate('items.0.product');
Defensive patterns

Strategy: type-guard

Validate before calling

function populateAt(doc, index, subPath) {
  if (typeof index !== 'number') throw new TypeError('index required');
  return doc.populate(`${arrayPath}.${index}.${subPath}`);
}

Type guard

const mongoose = require('mongoose');
function isSubdocument(v) {
  return v != null && typeof v === 'object' && typeof v.$__schemaType === 'undefined' && v instanceof mongoose.Types.Subdocument;
}

Try / catch

try { element.populate('ref'); } catch (err) { if (/populate\(\) on nested docs/.test(err.message)) return rootDoc.populate(`${arrPath}.${i}.ref`); throw err; }

Prevention

When it happens

Trigger: Calling doc.arr[0].populate('user') — populate on an element of an array of subdocuments; also via variables that hold an array subdocument, e.g. const item = doc.arr[0]; item.populate('user').

Common situations: Holding a reference to an array element in application code and trying to hydrate its refs; porting code that populated on standalone documents to nested arrays.

Related errors


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