{"record":{"id":"2f816498d60d8841","repo":"Automattic/mongoose","slug":"field-i-is-not-in-schema-and-strict-mode-is-s","errorCode":null,"errorMessage":"Field `${i}` is not in schema and strict mode is set to throw.","messagePattern":"Field `(.+?)` is not in schema and strict mode is set to throw\\.","errorType":"exception","errorClass":"StrictModeError","httpStatus":null,"severity":"error","filePath":"lib/document.js","lineNumber":823,"sourceCode":"    } else if (!schemaType) {\n      // Handle strictRead: filter unknown fields during document hydration from DB\n      if (strictRead === 'throw') {\n        throw new StrictModeError(path, 'Field `' + path + '` is not in schema and strictRead is set to throw.');\n      } else if (strictRead === true) {\n        // Skip this field - do not store in _doc\n        continue;\n      }\n      doc[i] = value;\n      if (!strict && !prefix) {\n        self[i] = value;\n      } else if (opts?.virtuals && (i in docSchema.virtuals)) {\n        self[i] = value;\n      } else if (opts?.strict === 'throw') {\n        // Only use strict: 'throw' semantics if explicit `strict: 'throw'` option\n        // passed in, like via `MyModel.hydrate(obj, null, { strict: 'throw' })`\n        // This is for backwards compatibility - strict: 'throw' at the schema level\n        // does not apply to documents loaded from the db.\n        throw new StrictModeError(i);\n      }\n    } else {\n      // Retain order when overwriting defaults\n      if (Object.hasOwn(doc, i) && value !== void 0 && !opts.hydratedPopulatedDocs) {\n        delete doc[i];\n      }\n      if (value === null) {\n        doc[i] = schemaType._castNullish(null);\n      } else if (value !== undefined) {\n        const wasPopulated = value.$__ == null ? null : value.$__.wasPopulated;\n\n        if (schemaType && !wasPopulated && !opts.hydratedPopulatedDocs) {\n          try {\n            if (opts?.setters) {\n              // Call applySetters with `init = false` because otherwise setters are a noop\n              const overrideInit = false;\n              doc[i] = schemaType.applySetters(value, self, overrideInit, null, opts);\n            } else {","sourceCodeStart":805,"sourceCodeEnd":841,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/document.js#L805-L841","documentation":"StrictModeError thrown during hydration when the caller explicitly passed `strict: 'throw'` in the hydration options (e.g. `MyModel.hydrate(obj, null, { strict: 'throw' })`) and the object contains a field with no schema path. Schema-level `strict: 'throw'` deliberately does NOT apply to documents loaded from the db - only this explicit per-call option triggers the throw, for backwards compatibility.","triggerScenarios":"Calling `MyModel.hydrate(obj, null, { strict: 'throw' })` (or any init path where opts.strict === 'throw') with an object that has keys not defined in the schema.","commonSituations":"Teams porting write-time `strict: 'throw'` checks to hydrate(); hydrating raw aggregation output or third-party data containing extra keys; Mongoose 7/8 behavior where schema-level strict: 'throw' no longer applies to db-loaded documents.","solutions":["Drop `strict: 'throw'` from the hydrate options so unknown keys are tolerated","Whitelist keys against the schema before hydrating","Add the extra fields to the schema","Use the dedicated `strictRead` option if you want a read-time policy"],"exampleFix":"// before\nconst doc = MyModel.hydrate(raw, null, { strict: 'throw' }); // raw has extra keys -> StrictModeError\n\n// after\nconst paths = new Set(Object.keys(MyModel.schema.paths).concat(['_id']));\nconst clean = Object.fromEntries(Object.entries(raw).filter(([k]) => paths.has(k)));\nconst doc = MyModel.hydrate(clean, null, { strict: 'throw' });","handlingStrategy":"try-catch","validationCode":"// Strip unknown keys before hydrating with strict: 'throw'\nconst known = new Set(Object.keys(MyModel.schema.paths).concat(['_id']));\nconst clean = Object.fromEntries(Object.entries(raw).filter(([k]) => known.has(k)));\nconst doc = MyModel.hydrate(clean, null, { strict: 'throw' });","typeGuard":null,"tryCatchPattern":"try {\n  const doc = MyModel.hydrate(raw, null, { strict: 'throw' });\n} catch (err) {\n  if (err instanceof mongoose.Error.StrictModeError) {\n    // input object has extra keys; whitelist them or drop the strict option\n  } else { throw err; }\n}","preventionTips":["Remember schema-level strict: 'throw' does not apply to hydration; only per-call options do","Whitelist foreign data (aggregation output, other APIs) against the schema before hydrate()"],"tags":["mongoose","hydrate","strict-mode","schema"],"backgroundTag":"strict-mode-unknown-field","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}