{"record":{"id":"2f91a49758e35483","repo":"Automattic/mongoose","slug":"field-path-is-not-in-schema-and-strictread-is","errorCode":null,"errorMessage":"Field `${path}` is not in schema and strictRead is set to throw.","messagePattern":"Field `(.+?)` is not in schema and strictRead is set to throw\\.","errorType":"exception","errorClass":"StrictModeError","httpStatus":null,"severity":"error","filePath":"lib/document.js","lineNumber":788,"sourceCode":"  for (let index = 0; index < len; ++index) {\n    i = keys[index];\n    // avoid prototype pollution\n    if (specialProperties.has(i)) {\n      continue;\n    }\n    path = prefix ? prefix + i : i;\n    schemaType = docSchema.path(path);\n    // Should still work if not a model-level discriminator, but should not be\n    // necessary. This is *only* to catch the case where we queried using the\n    // base model and the discriminated model has a projection\n    if (docSchema.$isRootDiscriminator && !self.$__isSelected(path)) {\n      continue;\n    }\n\n    const value = obj[i];\n    if (!schemaType && strictRead && docSchema.pathType(path) === 'adhocOrUndefined') {\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        continue;\n      }\n    }\n\n    if (!schemaType && utils.isPOJO(value)) {\n      // assume nested object\n      if (!doc[i]) {\n        doc[i] = {};\n        if (!strict && !(i in docSchema.tree) && !(i in docSchema.methods) && !(i in docSchema.virtuals)) {\n          self[i] = doc[i];\n        } else if (opts?.virtuals && (i in docSchema.virtuals)) {\n          self[i] = doc[i];\n        }\n      }\n      init(self, value, doc[i], opts, path + '.');\n    } else if (!schemaType) {\n      // Handle strictRead: filter unknown fields during document hydration from DB","sourceCodeStart":770,"sourceCodeEnd":806,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/document.js#L770-L806","documentation":"StrictModeError thrown while Mongoose hydrates a document (init from a query result or Model.hydrate()). The stored object contains a field that has no matching path in the schema, and `strictRead` is set to 'throw'. `strictRead` only governs reads: by default unknown DB fields are kept on the hydrated document; `strictRead: true` filters them out and 'throw' raises this error instead.","triggerScenarios":"Running find()/findOne()/findById() or Model.hydrate() on a model whose schema (or hydration options) sets `strictRead: 'throw'` while stored documents carry fields not declared in the schema - e.g. fields dropped during a schema refactor, or extra keys written by another service sharing the collection.","commonSituations":"Schema evolution where old documents still store removed fields; multi-service collections with divergent schemas; enabling strictRead: 'throw' to audit legacy data hygiene; querying the base model when discriminator models define extra fields.","solutions":["Set `strictRead: true` instead of 'throw' so unknown fields are silently dropped on read","Re-add the offending field to the schema (e.g. with `select: false`) until the data is migrated","Migrate stored documents with an `$unset` update to strip stale fields","Use a projection so unknown fields are never fetched"],"exampleFix":"// before\nconst schema = new Schema({ name: String }, { strictRead: 'throw' });\nconst docs = await Model.find(); // old docs still contain `legacyField` -> StrictModeError\n\n// after (acknowledge the field, or drop it silently)\nconst schema = new Schema(\n  { name: String, legacyField: { type: Schema.Types.Mixed, select: false } },\n  { strictRead: 'throw' }\n);\n// or simply: { strictRead: true }","handlingStrategy":"try-catch","validationCode":"// Detect schema drift before hydrating raw objects\nconst known = new Set(Object.keys(MyModel.schema.paths).concat(['_id']));\nconst unknown = Object.keys(rawDoc).filter(k => !known.has(k));\nif (unknown.length > 0) {\n  // strip or log unknown keys before strictRead: 'throw' sees them\n  for (const k of unknown) delete rawDoc[k];\n}","typeGuard":"function isKnownField(model, key) {\n  return key === '_id' || model.schema.path(key) != null;\n}","tryCatchPattern":"try {\n  const docs = await MyModel.find(query);\n} catch (err) {\n  if (err instanceof mongoose.Error.StrictModeError) {\n    // stored data has fields the schema does not know; parse the path from err.message\n    // then either add the path to the schema or relax strictRead to true\n  } else {\n    throw err;\n  }\n}","preventionTips":["When removing a field from a schema, ship a $unset migration in the same release","Prefer strictRead: true unless a hard failure on unknown fields is the explicit goal","Share one schema definition across all services that write the same collection"],"tags":["mongoose","strict-read","hydration","schema","strict-mode"],"backgroundTag":"strict-mode-unknown-field","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}