Automattic/mongoose · error · CastError
Cast to ${this.instance} failed for value "${value}" (type $
Error message
Cast to ${this.instance} failed for value "${value}" (type ${valueType}) at path "${this.path}" What it means
CastError thrown from SchemaType.prototype.cast() when a path that is currently populated is assigned a non-object value (a primitive, string, number, or Buffer). A populated path must hold a document of the populated model, so scalars cannot be cast; without populate the same value (e.g. an ObjectId string) would cast fine.
Source
Thrown at lib/schemaType.js:1713
* ignore
*/
SchemaType.prototype._castRef = function _castRef(value, doc, init, options) {
if (value == null) {
return value;
}
if (value.$__ != null) {
value.$__.wasPopulated = value.$__.wasPopulated || { value: value._doc._id };
return value;
}
// setting a populated path
if (Buffer.isBuffer(value) || !utils.isObject(value)) {
if (init) {
return value;
}
throw new CastError(this.instance, value, this.path, null, this);
}
// Handle the case where user directly sets a populated
// path to a plain object; cast to the Model used in
// the population query.
const path = doc.$__fullPath(this.path, true);
const owner = doc.ownerDocument();
const pop = owner.$populated(path, true);
let ret = value;
if (!doc.$__.populated ||
!doc.$__.populated[path] ||
!doc.$__.populated[path].options ||
!doc.$__.populated[path].options.options ||
!doc.$__.populated[path].options.options.lean) {
const PopulatedModel = pop ? pop.options[populateModelSymbol] : owner.constructor.db.model(this.options.ref);
ret = PopulatedModel.hydrate(value, null, options);
ret.$__.wasPopulated = { value: ret._doc._id, options: { [populateModelSymbol]: PopulatedModel } };View on GitHub (pinned to 49cdab0136)
Solutions
- Assign an object with the _id: doc.owner = { _id: ownerId }
- Or depopulate first, then set the scalar: doc.depopulate('owner'); doc.owner = ownerId;
- Or assign a real model instance: doc.owner = await User.findById(ownerId)
Example fix
// before
await doc.populate('owner');
doc.owner = '64b1f0c2e4b0a1d2c3e4f5a6'; // CastError
// after
await doc.populate('owner');
doc.owner = { _id: '64b1f0c2e4b0a1d2c3e4f5a6' }; Defensive patterns
Strategy: try-catch
Validate before calling
function setRef(doc, path, value) {
if (doc.$populated && doc.$populated(path) && (typeof value !== 'object' || value === null || Buffer.isBuffer(value))) {
doc.depopulate(path);
}
doc.set(path, value);
} Type guard
function isPopulatedDocValue(value) {
return value != null && typeof value === 'object' && !Buffer.isBuffer(value);
} Try / catch
try { doc.owner = rawId; } catch (err) { if (err.name === 'CastError' && err.path === 'owner') { doc.owner = { _id: rawId }; } else throw err; } Prevention
- After populate, treat ref paths as holding documents — assign objects or model instances
- Centralize ref assignment in a setter that depopulates first when a scalar arrives
- Watch for request-body spreads onto populated docs in integration tests
When it happens
Trigger: doc.populate('owner').then(() => { doc.owner = '64b1...'; }) — assigning a raw id string to a populated ref path; doc.set('owner', 5) or assigning a Buffer while the path is populated.
Common situations: Trying to reset a populated reference back to an _id after populate; assigning values parsed from JSON/web requests onto populated documents; spreading request bodies onto populated docs.
Related errors
- Invalid addFields() argument. Must be an object
- `refPath` must be a string or a function that returns a stri
- Document.prototype.populate() no longer accepts a callback
- Expected path "${path}" to be populated
- For your own good, using `document.save()` to update an arra
AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21).
Data as JSON: /api/errors/a3d63fe0a6ffeeb0.
Report an issue: GitHub.