Automattic/mongoose · error · MongooseError
The provided class ${name} must extend Model
Error message
The provided class ${name} must extend Model What it means
Model.discriminator() accepts either (name, schema) or a pre-defined class as its first argument. When a function/class is passed, it must extend Model — Mongoose wires discriminator inheritance through the Model prototype chain and cannot attach arbitrary constructors. This MongooseError is thrown when the provided class's prototype is not an instance of Model (including classes from a different mongoose copy).
Source
Thrown at lib/model.js:1005
* @param {string} name discriminator model name
* @param {Schema} schema discriminator model schema
* @param {object|string} [options] If string, same as `options.value`.
* @param {string} [options.value] the string stored in the `discriminatorKey` property. If not specified, Mongoose uses the `name` parameter.
* @param {boolean} [options.clone=true] By default, `discriminator()` clones the given `schema`. Set to `false` to skip cloning.
* @param {boolean} [options.overwriteModels=false] by default, Mongoose does not allow you to define a discriminator with the same name as another discriminator. Set this to allow overwriting discriminators with the same name.
* @param {boolean} [options.mergeHooks=true] By default, Mongoose merges the base schema's hooks with the discriminator schema's hooks. Set this option to `false` to make Mongoose use the discriminator schema's hooks instead.
* @param {boolean} [options.mergePlugins=true] By default, Mongoose merges the base schema's plugins with the discriminator schema's plugins. Set this option to `false` to make Mongoose use the discriminator schema's plugins instead.
* @return {Model} The newly created discriminator model
* @api public
*/
Model.discriminator = function(name, schema, options) {
let model;
if (typeof name === 'function') {
model = name;
name = utils.getFunctionName(model);
if (!(model.prototype instanceof Model)) {
throw new MongooseError('The provided class ' + name + ' must extend Model');
}
}
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();
}
View on GitHub (pinned to 49cdab0136)
Solutions
- Let Mongoose create the class: const Clicked = Events.discriminator('Clicked', clickedSchema)
- Only pass a class when it genuinely extends Model from the same mongoose import: class Clicked extends Model {}
- Do not pass plain constructors or domain classes expecting them to become models
Example fix
// before
class ClickedEvent { constructor(props) { Object.assign(this, props); } }
Events.discriminator(ClickedEvent, clickedSchema); // throws: must extend Model
// after
const ClickedEvent = Events.discriminator('Clicked', clickedSchema); Defensive patterns
Strategy: type-guard
Validate before calling
// Validate a class before passing it to discriminator()
function isModelClass(cls) {
return typeof cls === 'function' && (cls.prototype instanceof mongoose.Model || cls === mongoose.Model);
}
if (isModelClass(ClickedEvent)) Events.discriminator(ClickedEvent, clickedSchema); Type guard
function isModelClass(cls) {
return typeof cls === 'function' && (cls.prototype instanceof mongoose.Model || cls === mongoose.Model);
} Try / catch
try {
Events.discriminator(nameOrClass, schema);
} catch (err) {
if (err instanceof mongoose.MongooseError && /must extend Model/.test(err.message)) {
// re-register with just a name: Events.discriminator('Clicked', schema)
} else throw err;
} Prevention
- Default to discriminator(name, schema) and let Mongoose build the class
- Only pass a class that extends Model from the same mongoose import you registered the base with
- In TypeScript, derive class types via ModelType<InferSchemaType<S>> rather than hand-written classes
When it happens
Trigger: BaseModel.discriminator(SomeRandomClass, schema), BaseModel.discriminator(class Event {}, eventSchema), or passing a class that extends a Model imported from a duplicate mongoose instance; then calling the discriminator registration.
Common situations: Trying to hook discriminators into existing domain classes; TypeScript classes declared without `extends Model`; plugins registering user-supplied classes; duplicate-mongoose setups where the extends chain crosses copies.
Related errors
- 2nd argument to `Model` constructor must be a POJO or string
- First argument to `Model` constructor must be an object, **n
- Cannot overwrite `${name}` model once compiled.
- Collection name must be a string
- Arguments must be aggregate pipeline operators
AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21).
Data as JSON: /api/errors/6f4550aabe7f5ba1.
Report an issue: GitHub.