Automattic/mongoose · error · MongooseError

Query must have an associated model before executing

Error message

Query must have an associated model before executing

What it means

exec() needs a Model to know which collection to hit and which schema to use for casting. If `query.model` is null — typically because the Query was constructed standalone instead of through a model — Mongoose throws before executing. Model-derived queries (Model.find(), doc.$where, etc.) always carry the model, so this error almost always means a raw `new Query()` was used.

Source

Thrown at lib/query.js:4758

 * @return {Promise}
 * @api public
 */

Query.prototype.exec = async function exec(op) {
  if (typeof op === 'function' || (arguments.length >= 2 && typeof arguments[1] === 'function')) {
    throw new MongooseError('Query.prototype.exec() no longer accepts a callback');
  }

  this._validateOp();
  if (typeof op === 'string') {
    this.op = op;
  }

  if (this.op == null) {
    throw new MongooseError('Query must have `op` before executing');
  }
  if (this.model == null) {
    throw new MongooseError('Query must have an associated model before executing');
  }

  const thunk = opToThunk.get(this.op);
  if (!thunk) {
    throw new MongooseError('Query has invalid `op`: "' + this.op + '"');
  }

  if (this.options?.sort && typeof this.options.sort === 'object' && Object.hasOwn(this.options.sort, '')) {
    throw new MongooseError('Invalid field "" passed to sort()');
  }

  if (this._execCount > 0) {
    let str = this.toString();
    if (str.length > 60) {
      str = str.slice(0, 60) + '...';
    }
    throw new MongooseError('Query was already executed: ' + str);
  }

View on GitHub (pinned to 49cdab0136)

Solutions

  1. Create queries through a model: `Model.find({...}).exec()` instead of `new Query(...)`.
  2. If you must reuse a standalone query, bind it first: `query.model = MyModel` (or construct it as `new Query({}, null, Model)`).
  3. Keep raw query objects as plain filter documents and pass them into Model.find(filter) at execution time.

Example fix

// before
const { Query } = require('mongoose');
await new Query({ name: 'x' }).find().exec(); // throws: Query must have an associated model

// after
await Model.find({ name: 'x' }).exec();
Defensive patterns

Strategy: validation

Validate before calling

function execQuery(query, Model) {
  if (query.model == null) query.model = Model;
  return query.exec();
}

Type guard

const queryHasModel = (q) => q.model != null;

Try / catch

try { await q.exec(); } catch (err) { if (err instanceof mongoose.Error && /associated model/.test(err.message)) { q.model = MyModel; return q.exec(); } throw err; }

Prevention

When it happens

Trigger: `new Query({ name: 'x' }).find().exec()` with no model bound; `new mongoose.Query()` then .find().exec(); losing the model by manually cloning query internals; calling exec on a query created from a deleted/undefined model variable.

Common situations: Using Query directly to build reusable filter objects and then executing them by mistake; dependency-order bugs where the query outlives its model import; porting mquery code into Mongoose.

Related errors


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