Automattic/mongoose · error · OverwriteModelError
Cannot overwrite `${name}` model once compiled.
Error message
Cannot overwrite `${name}` model once compiled. What it means
Thrown by Model.discriminator() (via OverwriteModelError) when a discriminator name is already registered on the same connection (this.db.models[name] exists). Mongoose refuses to silently replace a compiled model because existing documents, queries, and hooks hold references to the old constructor. The guard is bypassed only when the schema option `overwriteModels` is true or the `overwriteModels` argument is passed as true.
Source
Thrown at lib/model.js:1026
options = options || {};
const value = utils.isPOJO(options) ? options.value : options;
const clone = typeof options.clone === 'boolean' ? options.clone : true;
const mergePlugins = typeof options.mergePlugins === 'boolean' ? options.mergePlugins : true;
const overwriteModels = typeof options.overwriteModels === 'boolean' ? options.overwriteModels : false;
_checkContext(this, 'discriminator');
if (utils.isObject(schema) && !schema.instanceOfSchema) {
schema = new Schema(schema);
}
if (schema instanceof Schema && clone) {
schema = schema.clone();
}
schema = discriminator(this, name, schema, value, mergePlugins, options.mergeHooks, overwriteModels);
if (this.db.models[name] && !schema.options.overwriteModels && !overwriteModels) {
throw new OverwriteModelError(name);
}
schema.$isRootDiscriminator = true;
schema.$globalPluginsApplied = true;
model = this.db.model(model || name, schema, this.$__collection.name);
this.discriminators[name] = model;
const d = this.discriminators[name];
Object.setPrototypeOf(d.prototype, this.prototype);
Object.defineProperty(d, 'baseModelName', {
value: this.modelName,
configurable: true,
writable: false
});
// apply methods and statics
applyMethods(d, schema);
applyStatics(d, schema);View on GitHub (pinned to 49cdab0136)
Solutions
- Reuse the existing model instead of re-registering: `const Clicked = Event.discriminators['ClickedLink'] ?? Event.discriminator('ClickedLink', clickedSchema)`
- Delete the stale registration first: `mongoose.connection.deleteModel('ClickedLink')` before recompiling
- Pass the overwrite flag: `Event.discriminator('ClickedLink', clickedSchema, { value: ..., mergeHooks: ... }, true)` or set `overwriteModels: true` in the schema options
- Centralize all model definitions in one module that runs once per process, and export the compiled models from there
Example fix
// before (runs on every hot reload)
Event.discriminator('ClickedLink', clickedSchema); // OverwriteModelError on 2nd run
// after
const ClickedLink =
Event.discriminators['ClickedLink'] ||
Event.discriminator('ClickedLink', clickedSchema); Defensive patterns
Strategy: validation
Validate before calling
// Before registering, check every registry the discriminator would land in const getDiscriminator = (Model, name, schema) => Model.discriminators?.[name] || mongoose.models[name] || mongoose.connection.models[name] || Model.discriminator(name, schema);
Prevention
- Define every model/discriminator in exactly one module and import the compiled model elsewhere — never re-run registration
- In dev with HMR (Next.js/NestJS), add a cleanup hook: `mongoose.connection.deleteModel(name)` or use the global mongoose cache pattern
- When overriding is intentional, pass the `overwriteModels` argument or schema option explicitly so the intent is visible in review
When it happens
Trigger: Calling `Event.discriminator('ClickedLink', clickedSchema)` twice with the same name on one connection; a discriminator name that collides with an already-registered base or sibling model; re-executing a model-definition module against a live connection (Next.js/NestJS HMR, Jest watch) so `mongoose.model()` runs again.
Common situations: Hot-reloading dev servers that re-import model files; test suites that recompile models on every run without resetting mongoose; monorepos where the same model module is loaded twice through different resolve paths; serverless environments that re-use a cached connection across warm invocations.
Related errors
- The provided class ${name} must extend Model
- Arguments must be aggregate pipeline operators
- Invalid addFields() argument. Must be an object
- Invalid project() argument. Must be string or object
- Aggregate `near()` must be called with non-nullish argument
AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21).
Data as JSON: /api/errors/821fed06268824ce.
Report an issue: GitHub.