{"record":{"id":"9cd70fddbfd52f86","repo":"Automattic/mongoose","slug":"2nd-argument-to-model-constructor-must-be-a-pojo","errorCode":null,"errorMessage":"2nd argument to `Model` constructor must be a POJO or string, **not** a schema. Make sure you're calling `mongoose.model()`, not `mongoose.Model()`.","messagePattern":"2nd argument to `Model` constructor must be a POJO or string, \\*\\*not\\*\\* a schema\\. Make sure you're calling `mongoose\\.model\\(\\)`, not `mongoose\\.Model\\(\\)`\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"lib/model.js","lineNumber":134,"sourceCode":" *     // You also use a model to create queries:\n *     const userFromDb = await UserModel.findOne({ name: 'Foo' });\n *\n * @param {object} doc values for initial set\n * @param {object} [fields] optional object containing the fields that were selected in the query which returned this document. You do **not** need to set this parameter to ensure Mongoose handles your [query projection](https://mongoosejs.com/docs/api/query.html#Query.prototype.select()).\n * @param {object} [options] optional object containing the options for the document.\n * @param {boolean} [options.defaults=true] if `false`, skip applying default values to this document.\n * @param {boolean} [options.skipId=false] By default, Mongoose document if one is not provided and the document's schema does not override Mongoose's default `_id`. Set `skipId` to `true` to skip this generation step.\n * @inherits Document https://mongoosejs.com/docs/api/document.html\n * @event `error`: If listening to this event, 'error' is emitted when a document was saved and an `error` occurred. If not listening, the event bubbles to the connection used to create this Model.\n * @event `index`: Emitted after `Model#ensureIndexes` completes. If an error occurred it is passed with the event.\n * @event `index-single-start`: Emitted when an individual index starts within `Model#ensureIndexes`. The fields and options being used to build the index are also passed with the event.\n * @event `index-single-done`: Emitted when an individual index finishes within `Model#ensureIndexes`. If an error occurred it is passed with the event. The fields, options, and index name are also passed.\n * @api public\n */\n\nfunction Model(doc, fields, options) {\n  if (fields instanceof Schema) {\n    throw new TypeError('2nd argument to `Model` constructor must be a POJO or string, ' +\n      '**not** a schema. Make sure you\\'re calling `mongoose.model()`, not ' +\n      '`mongoose.Model()`.');\n  }\n  if (typeof doc === 'string') {\n    throw new TypeError('First argument to `Model` constructor must be an object, ' +\n      '**not** a string. Make sure you\\'re calling `mongoose.model()`, not ' +\n      '`mongoose.Model()`.');\n  }\n  Document.call(this, doc, fields, options);\n}\n\n/**\n * Inherits from Document.\n *\n * All Model.prototype features are available on\n * top level (non-sub) documents.\n * @api private\n */","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/model.js#L116-L152","documentation":"Mongoose's base Model constructor takes (doc, fields, options) — never a Schema. This TypeError guards against the classic mistake of trying to compile or instantiate a model via the Model constructor directly with a schema (new mongoose.Model(doc, schema)). Model classes must be compiled through mongoose.model(name, schema) (or connection.model(...)); only the compiled class is instantiated with documents.","triggerScenarios":"const User = new mongoose.Model({}, userSchema), new SomeModel(doc, someSchema), or class Foo extends mongoose.Model {} invoked as new Foo(schema). Usually copy-paste or autocomplete substituting mongoose.Model for mongoose.model.","commonSituations":"Misreading docs and treating Model as a factory; TypeScript codemods rewriting mongoose.model into new Model; old code that subclassed Model directly; editor autocomplete picking Model over model.","solutions":["Compile the model first: const User = mongoose.model('User', userSchema)","Instantiate with plain documents: new User({ name: 'x' })","For multiple connections use connection.model('User', userSchema)"],"exampleFix":"// before\nconst User = new mongoose.Model({}, userSchema); // TypeError\n\n// after\nconst User = mongoose.model('User', userSchema);\nconst doc = new User({ name: 'x' });","handlingStrategy":"type-guard","validationCode":"// Compile models through the registry only\nfunction compileModel(name, schema) {\n  if (!(schema instanceof mongoose.Schema)) throw new Error('Expected a mongoose.Schema');\n  return mongoose.model(name, schema);\n}","typeGuard":"const isModelConstructorCallSafe = (fields) => !(fields instanceof mongoose.Schema);","tryCatchPattern":"try {\n  new SomeModel(doc);\n} catch (err) {\n  if (err instanceof TypeError && /2nd argument to `Model`/.test(err.message)) {\n    // you passed a schema: switch to mongoose.model(name, schema)\n  } else throw err;\n}","preventionTips":["Always compile with mongoose.model()/connection.model() and instantiate only the returned class","Reserve `import { Model }` for type positions (extends Model<T>), never for construction","Lint for `new mongoose.Model` and `Model\\(` direct calls in code review"],"tags":["mongoose","model","schema","constructor","api-misuse"],"backgroundTag":"model-constructor-misuse","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}