Automattic/mongoose · error · MongooseError
`Model.${fnName}()` cannot run without a model as `this`. Ma
Error message
`Model.${fnName}()` cannot run without a model as `this`. Make sure you are calling `MyModel.${fnName}()` where `MyModel` is a Mongoose model. What it means
Model statics such as discriminator(), init(), syncIndexes() begin with `_checkContext(this, fnName)`, which throws this MongooseError when `this` is null, undefined, or the global object. It means the function was detached from its model — typically by destructuring the method off the model or passing the bare function reference where it is later invoked unbound. The model is a function (class), so its statics rely on a correct receiver.
Source
Thrown at lib/model.js:1066
submodel.discriminators = submodel.discriminators || {};
submodel.discriminators[name] =
model.__subclass(model.db, schema, submodel.collection.name);
}
}
return d;
};
/**
* Make sure `this` is a model
* @api private
*/
function _checkContext(ctx, fnName) {
// Check context, because it is easy to mistakenly type
// `new Model.discriminator()` and get an incomprehensible error
if (ctx == null || ctx === global) {
throw new MongooseError('`Model.' + fnName + '()` cannot run without a ' +
'model as `this`. Make sure you are calling `MyModel.' + fnName + '()` ' +
'where `MyModel` is a Mongoose model.');
} else if (ctx[modelSymbol] == null) {
throw new MongooseError('`Model.' + fnName + '()` cannot run without a ' +
'model as `this`. Make sure you are not calling ' +
'`new Model.' + fnName + '()`');
}
}
// Model (class) features
/*!
* Give the constructor the ability to emit events.
*/
for (const i in EventEmitter.prototype) {
Model[i] = EventEmitter.prototype[i];
}View on GitHub (pinned to 49cdab0136)
Solutions
- Call the method on the model itself: `await User.syncIndexes()` instead of a destructured `syncIndexes()`
- Wrap in an arrow function when passing as a callback: `server.on('start', () => User.init())`
- Bind explicitly if you need a reference: `const init = User.init.bind(User)`
- Search for destructuring of model statics (`const { X } = SomeModel`) in the file named in the stack trace
Example fix
// before
const { syncIndexes } = User;
await syncIndexes(); // throws: no model as `this`
// after
await User.syncIndexes(); Defensive patterns
Strategy: type-guard
Validate before calling
// Receiver sanity check before invoking a stored static
const callStatic = (maybeModel, fn, ...args) => {
if (!isMongooseModel(maybeModel)) {
throw new TypeError('Expected a compiled mongoose Model as receiver');
}
return maybeModel[fn](...args);
}; Type guard
function isMongooseModel(v) {
return typeof v === 'function' &&
typeof v.modelName === 'string' &&
v.db != null &&
typeof v.findOne === 'function' &&
typeof v.discriminator === 'function';
} Prevention
- Never destructure statics off a Model (`const { init } = User` is a bug waiting to happen)
- When handing model statics to event emitters or frameworks, always wrap: `() => User.init()` or `.bind(User)`
- Enable @typescript-eslint's unbound-method rule so detached methods are flagged at lint time
When it happens
Trigger: `const { syncIndexes } = User; syncIndexes();`; passing `User.init` directly as a callback (`server.on('start', User.init)`) so it is called with an undefined receiver; `Promise.all([Model.init, Model.ensureIndexes])` (missing invocation is fine, but `.map(Model.init)` is not); `const fn = Model.discriminator; fn('X', schema)`.
Common situations: Refactors that destructure model methods for brevity; passing statics as event handlers or to frameworks that rebind `this` (Mocha, Express middleware chains); code ported from plain-object service classes where destructuring is safe.
Related errors
- `Model.${fnName}()` cannot run without a model as `this`. Ma
- 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/80a0f96729d7cd43.
Report an issue: GitHub.