Automattic/mongoose · error · MongooseError

No populated model found for path `${this[arrayPathSymbol]}`

Error message

No populated model found for path `${this[arrayPathSymbol]}`. This is likely a bug in Mongoose, please report an issue on github.com/Automattic/mongoose.

What it means

Internal invariant in MongooseArray._cast(): the array's path reports itself as populated, but the populate metadata's options[populateModelSymbol] is null, so Mongoose cannot determine which model to cast the pushed value to. Mongoose itself labels this 'likely a bug' — the populated state is inconsistent rather than a user input problem.

Source

Thrown at lib/types/array/methods/index.js:268

   * @method _cast
   * @api private
   * @memberOf MongooseArray
   */

  _cast(value) {
    let populated = false;
    let Model;

    const parent = this[arrayParentSymbol];
    if (parent) {
      populated = parent.$populated(this[arrayPathSymbol], true);
    }

    if (populated && value != null) {
      // cast to the populated Models schema
      Model = populated.options[populateModelSymbol];
      if (Model == null) {
        throw new MongooseError('No populated model found for path `' + this[arrayPathSymbol] + '`. This is likely a bug in Mongoose, please report an issue on github.com/Automattic/mongoose.');
      }

      // only objects are permitted so we can safely assume that
      // non-objects are to be interpreted as _id
      if (Buffer.isBuffer(value) ||
          isBsonType(value, 'ObjectId') || !utils.isObject(value)) {
        value = { _id: value };
      }

      // gh-2399
      // we should cast model only when it's not a discriminator
      const isDisc = value.schema?.discriminatorMapping?.key !== undefined;
      if (!isDisc) {
        value = new Model(value);
      }
      return this[arraySchemaSymbol].embeddedSchemaType.applySetters(value, parent, true);
    }

View on GitHub (pinned to 49cdab0136)

Solutions

  1. Upgrade to the latest Mongoose patch release — this guard exists for real fixed bugs
  2. If it reproduces on the latest version, file an issue at github.com/Automaltic/mongoose with a minimal repro
  3. As a workaround, replace the whole array instead of pushing into a populated one: doc.arr = [...doc.arr.filter(x => cond), newItem]
  4. Check that ref/refPath on the path always resolves to a registered model

Example fix

// before
doc.populatedArr.push(newItem); // internal model symbol missing
// after (workaround)
doc.populatedArr = doc.populatedArr.concat([newItem]);
Defensive patterns

Strategy: try-catch

Validate before calling

const POPULATE_MODEL = require('mongoose').populateModelSymbol ?? null; // internal
function canPushIntoPopulated(doc, path) {
  const pop = doc.$populated && doc.$populated(path, true);
  return !pop || (pop.options && pop.options.model != null);
}

Type guard

function isSafeToPush(doc, path) { const pop = doc.$populated?.(path, true); return pop == null || pop.options?.model != null; }

Try / catch

try { doc.arr.push(item); } catch (err) { if (/No populated model found/.test(err.message)) { doc.arr = doc.arr.concat([item]); reportUpstream(err, doc); } else throw err; }

Prevention

When it happens

Trigger: Calling doc.populatedArr.push(value) or doc.populatedArr[i] = value when the populate metadata lacks the internal model symbol — after manual $populated manipulation, populate() with a refPath that resolves to a missing model, or an actual Mongoose regression.

Common situations: Appearing after upgrading Mongoose versions; using refPath with discriminators; code that manually crafts populated state or reuses populate options objects across documents.

Related errors


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