{"record":{"id":"ec31966cf97b5c64","repo":"Automattic/mongoose","slug":"mongoose-does-not-support-calling-populate-on-ne","errorCode":null,"errorMessage":"Mongoose does not support calling populate() on nested docs. Instead of `doc.arr[0].populate(\"path\")`, use `doc.populate(\"arr.0.path\")`","messagePattern":"Mongoose does not support calling populate\\(\\) on nested docs\\. Instead of `doc\\.arr\\[0\\]\\.populate\\(\"path\"\\)`, use `doc\\.populate\\(\"arr\\.0\\.path\"\\)`","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/types/arraySubdocument.js","lineNumber":89,"sourceCode":" */\n\nArraySubdocument.prototype.$setIndex = function(index) {\n  this.__index = index;\n\n  if (this.$__?.validationError != null) {\n    const keys = Object.keys(this.$__.validationError.errors);\n    for (const key of keys) {\n      this.invalidate(key, this.$__.validationError.errors[key]);\n    }\n  }\n};\n\n/*!\n * ignore\n */\n\nArraySubdocument.prototype.populate = function() {\n  throw new Error('Mongoose does not support calling populate() on nested ' +\n    'docs. Instead of `doc.arr[0].populate(\"path\")`, use ' +\n    '`doc.populate(\"arr.0.path\")`');\n};\n\n/*!\n * ignore\n */\n\nArraySubdocument.prototype.$__removeFromParent = function() {\n  const _id = this._doc._id;\n  if (!_id) {\n    throw new Error('For your own good, Mongoose does not know ' +\n      'how to remove an ArraySubdocument that has no _id');\n  }\n  this.__parentArray.pull({ _id: _id });\n};\n\n/**","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/types/arraySubdocument.js#L71-L107","documentation":"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.","triggerScenarios":"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').","commonSituations":"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.","solutions":["Call populate on the root document with the indexed dotted path: doc.populate('arr.0.user')","For multiple elements use the parent path (doc.populate('arr.user')) — Mongoose populates every element","Await the result: await doc.populate('arr.0.user')"],"exampleFix":"// before\ndoc.items[0].populate('product');\n// after\nawait doc.populate('items.0.product');","handlingStrategy":"type-guard","validationCode":"function populateAt(doc, index, subPath) {\n  if (typeof index !== 'number') throw new TypeError('index required');\n  return doc.populate(`${arrayPath}.${index}.${subPath}`);\n}","typeGuard":"const mongoose = require('mongoose');\nfunction isSubdocument(v) {\n  return v != null && typeof v === 'object' && typeof v.$__schemaType === 'undefined' && v instanceof mongoose.Types.Subdocument;\n}","tryCatchPattern":"try { element.populate('ref'); } catch (err) { if (/populate\\(\\) on nested docs/.test(err.message)) return rootDoc.populate(`${arrPath}.${i}.ref`); throw err; }","preventionTips":["Never call populate() on anything but the root document or a Model","Always build the dotted path including the array index: 'arr.0.ref'","Encapsulate populate calls in one repository layer to avoid scattered misuse"],"tags":["mongoose","populate","array-subdocument"],"backgroundTag":"unsupported-populate-call","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}