Automattic/mongoose · error · MongooseError
Expected path "${path}" to be populated
Error message
Expected path "${path}" to be populated What it means
Document.prototype.$assertPopulated(path, values) is a fail-fast guard: it optionally $set()s the second argument, then throws MongooseError if $populated(path) is falsy, i.e. the path is not currently populated. It exists so code that depends on populated data crashes immediately with a clear path name instead of silently reading raw ObjectId refs.
Source
Thrown at lib/document.js:5064
* @return {Document} this
* @memberOf Document
* @method $assertPopulated
* @instance
* @api public
*/
Document.prototype.$assertPopulated = function $assertPopulated(path, values) {
if (Array.isArray(path)) {
path.forEach(p => this.$assertPopulated(p, values));
return this;
}
if (arguments.length > 1) {
this.$set(values);
}
if (!this.$populated(path)) {
throw new MongooseError(`Expected path "${path}" to be populated`);
}
return this;
};
/**
* Takes a populated field and returns it to its unpopulated state.
*
* #### Example:
*
* Model.findOne().populate('author').exec(function (err, doc) {
* console.log(doc.author.name); // Dr.Seuss
* console.log(doc.depopulate('author'));
* console.log(doc.author); // '5144cf8050f071d979c118a7'
* })
*
* If the path was not provided, then all populated fields are returned to their unpopulated state.
*View on GitHub (pinned to 49cdab0136)
Solutions
- Populate before asserting: await doc.populate('author') then doc.$assertPopulated('author').
- Branch instead of asserting when the path may legitimately be unpopulated: if (doc.$populated('author')) { ... }.
- Fix path typos: the path must match the schema path exactly, including full nested paths like 'author.address'.
- If you depopulated earlier, re-populate before asserting again.
Example fix
// before
const doc = await Model.findOne({ _id: id });
doc.$assertPopulated('author'); // throws: query had no .populate()
// after
const doc = await Model.findOne({ _id: id }).populate('author');
doc.$assertPopulated('author'); // ok
// or lazily:
if (!doc.$populated('author')) await doc.populate('author'); Defensive patterns
Strategy: validation
Validate before calling
async function ensurePopulated(doc, path) {
if (!doc.$populated(path)) {
await doc.populate(path);
}
return doc;
}
// usage
await ensurePopulated(doc, 'author');
doc.$assertPopulated('author'); Type guard
function isPopulated(doc, path) {
return doc.$populated(path) != null;
} Try / catch
try {
doc.$assertPopulated('author');
} catch (err) {
if (err instanceof mongoose.MongooseError && err.message.startsWith('Expected path')) {
await doc.populate('author'); // populate, then continue
} else {
throw err;
}
} Prevention
- Centralize populate requirements in the query layer so downstream code can assert safely.
- Prefer doc.$populated(path) checks where population is optional instead of unconditional asserts.
- Test every endpoint that reads populated fields so a dropped .populate() fails CI.
When it happens
Trigger: Calling doc.$assertPopulated('author') after a findOne() that lacked .populate('author'); after doc.$depopulate('author'); after save/depopulate reset the populated state; or with a typo'd path string that was never populated.
Common situations: Serializer or view code that assumes a path was populated upstream; a refactor dropped a .populate() call from the query; mixing populate and depopulate flows; nested path names not matching the schema exactly.
Related errors
- Mongoose does not support calling populate() on nested docs.
- Invalid addFields() argument. Must be an object
- Aggregate.prototype.exec() no longer accepts a callback
- `refPath` must be a string or a function that returns a stri
- Document.prototype.populate() no longer accepts a callback
AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21).
Data as JSON: /api/errors/48645d6489631f3f.
Report an issue: GitHub.