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

  1. Call the method on the model itself: `await User.syncIndexes()` instead of a destructured `syncIndexes()`
  2. Wrap in an arrow function when passing as a callback: `server.on('start', () => User.init())`
  3. Bind explicitly if you need a reference: `const init = User.init.bind(User)`
  4. 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

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


AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21). Data as JSON: /api/errors/80a0f96729d7cd43. Report an issue: GitHub.