{"record":{"id":"eb5a5351ca6330b6","repo":"Automattic/mongoose","slug":"query-must-have-an-associated-model-before-executi","errorCode":null,"errorMessage":"Query must have an associated model before executing","messagePattern":"Query must have an associated model before executing","errorType":"exception","errorClass":"MongooseError","httpStatus":null,"severity":"error","filePath":"lib/query.js","lineNumber":4758,"sourceCode":" * @return {Promise}\n * @api public\n */\n\nQuery.prototype.exec = async function exec(op) {\n  if (typeof op === 'function' || (arguments.length >= 2 && typeof arguments[1] === 'function')) {\n    throw new MongooseError('Query.prototype.exec() no longer accepts a callback');\n  }\n\n  this._validateOp();\n  if (typeof op === 'string') {\n    this.op = op;\n  }\n\n  if (this.op == null) {\n    throw new MongooseError('Query must have `op` before executing');\n  }\n  if (this.model == null) {\n    throw new MongooseError('Query must have an associated model before executing');\n  }\n\n  const thunk = opToThunk.get(this.op);\n  if (!thunk) {\n    throw new MongooseError('Query has invalid `op`: \"' + this.op + '\"');\n  }\n\n  if (this.options?.sort && typeof this.options.sort === 'object' && Object.hasOwn(this.options.sort, '')) {\n    throw new MongooseError('Invalid field \"\" passed to sort()');\n  }\n\n  if (this._execCount > 0) {\n    let str = this.toString();\n    if (str.length > 60) {\n      str = str.slice(0, 60) + '...';\n    }\n    throw new MongooseError('Query was already executed: ' + str);\n  }","sourceCodeStart":4740,"sourceCodeEnd":4776,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/query.js#L4740-L4776","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","solutions":["Create queries through a model: `Model.find({...}).exec()` instead of `new Query(...)`.","If you must reuse a standalone query, bind it first: `query.model = MyModel` (or construct it as `new Query({}, null, Model)`).","Keep raw query objects as plain filter documents and pass them into Model.find(filter) at execution time."],"exampleFix":"// before\nconst { Query } = require('mongoose');\nawait new Query({ name: 'x' }).find().exec(); // throws: Query must have an associated model\n\n// after\nawait Model.find({ name: 'x' }).exec();","handlingStrategy":"validation","validationCode":"function execQuery(query, Model) {\n  if (query.model == null) query.model = Model;\n  return query.exec();\n}","typeGuard":"const queryHasModel = (q) => q.model != null;","tryCatchPattern":"try { await q.exec(); } catch (err) { if (err instanceof mongoose.Error && /associated model/.test(err.message)) { q.model = MyModel; return q.exec(); } throw err; }","preventionTips":["Always create queries via Model.find() and friends.","Store plain filter objects, not bare Query instances, for reuse.","Bind a model explicitly when constructing Query manually: new Query({}, null, Model)."],"tags":["mongoose","query","exec","model-binding"],"backgroundTag":"mongoose-missing-query-model","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}