Automattic/mongoose · error · MongooseError
Attempting to remove virtual "${virtual}" that does not exis
Error message
Attempting to remove virtual "${virtual}" that does not exist. What it means
removeVirtual only deletes names present in schema.virtuals, which stores exact dotted names as they were defined. Passing a name that was never registered (or is already removed, or sits at a different nesting depth) throws instead of silently succeeding, to surface cleanup mistakes.
Source
Thrown at lib/schema.js:2831
delete branch[last];
}
/**
* Removes the given virtual or virtuals from the schema.
*
* @param {string|Array} path The virutal path(s) to remove.
* @returns {Schema} the Schema instance, or a mongoose error if the virtual does not exist.
* @api public
*/
Schema.prototype.removeVirtual = function(path) {
if (typeof path === 'string') {
path = [path];
}
if (Array.isArray(path)) {
for (const virtual of path) {
if (this.virtuals[virtual] == null) {
throw new MongooseError(`Attempting to remove virtual "${virtual}" that does not exist.`);
}
}
for (const virtual of path) {
delete this.paths[virtual];
delete this.virtuals[virtual];
if (virtual.indexOf('.') !== -1) {
mpath.unset(virtual, this.tree);
} else {
delete this.tree[virtual];
}
}
}
return this;
};
/**
* Loads an ES6 class into a schema. Maps [setters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set) + [getters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get), [static methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static),View on GitHub (pinned to 49cdab0136)
Solutions
- Inspect registered names first: `console.log(Object.keys(schema.virtuals))` and use the exact key.
- Guard removals: `if (schema.virtuals[name] != null) schema.removeVirtual(name)`.
- Build removal lists from Object.keys(schema.virtuals).filter(...) rather than duplicating names in config.
Example fix
// before
schema.removeVirtual('name.full'); // was actually defined as 'fullName'
// after
const target = Object.keys(schema.virtuals).find(n => n === 'fullName');
if (target) schema.removeVirtual(target); Defensive patterns
Strategy: validation
Validate before calling
const removeVirtualIfExists = (schema, name) => {
if (schema.virtuals[name] != null) schema.removeVirtual(name);
};
// or derive the list dynamically:
for (const name of Object.keys(schema.virtuals).filter(n => n.startsWith('tmp'))) {
schema.removeVirtual(name);
} Prevention
- Derive removal lists from schema.virtuals at runtime instead of duplicating names in config.
- Group virtual definitions and their removals in one module so they stay consistent.
- Remember names are exact dotted strings - 'a.b' and 'aB' are different virtuals.
When it happens
Trigger: `schema.removeVirtual('name.full')` when the virtual was defined as 'fullName'; removing the same virtual twice; plugins removing virtuals that optional configuration never created.
Common situations: Conditional schemas (feature flags) where a virtual may or may not exist; refactors renaming virtuals without updating teardown code; loops calling removeVirtual over a stale hardcoded list.
Related errors
- Invalid arguments
- Aggregate.prototype.exec() no longer accepts a callback
- Please provide an executor function
- `connection.model()` should not be run with `new`. If you ar
- The 2nd parameter to `mongoose.model()` should be a schema o
AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21).
Data as JSON: /api/errors/006e68f564067d98.
Report an issue: GitHub.