Automattic/mongoose · error · StrictModeError

Field `${path}` is not in schema and strictRead is set to th

Error message

Field `${path}` is not in schema and strictRead is set to throw.

What it means

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.

Source

Thrown at lib/document.js:788

  for (let index = 0; index < len; ++index) {
    i = keys[index];
    // avoid prototype pollution
    if (specialProperties.has(i)) {
      continue;
    }
    path = prefix ? prefix + i : i;
    schemaType = docSchema.path(path);
    // Should still work if not a model-level discriminator, but should not be
    // necessary. This is *only* to catch the case where we queried using the
    // base model and the discriminated model has a projection
    if (docSchema.$isRootDiscriminator && !self.$__isSelected(path)) {
      continue;
    }

    const value = obj[i];
    if (!schemaType && strictRead && docSchema.pathType(path) === 'adhocOrUndefined') {
      if (strictRead === 'throw') {
        throw new StrictModeError(path, 'Field `' + path + '` is not in schema and strictRead is set to throw.');
      } else if (strictRead === true) {
        continue;
      }
    }

    if (!schemaType && utils.isPOJO(value)) {
      // assume nested object
      if (!doc[i]) {
        doc[i] = {};
        if (!strict && !(i in docSchema.tree) && !(i in docSchema.methods) && !(i in docSchema.virtuals)) {
          self[i] = doc[i];
        } else if (opts?.virtuals && (i in docSchema.virtuals)) {
          self[i] = doc[i];
        }
      }
      init(self, value, doc[i], opts, path + '.');
    } else if (!schemaType) {
      // Handle strictRead: filter unknown fields during document hydration from DB

View on GitHub (pinned to 49cdab0136)

Solutions

  1. Set `strictRead: true` instead of 'throw' so unknown fields are silently dropped on read
  2. Re-add the offending field to the schema (e.g. with `select: false`) until the data is migrated
  3. Migrate stored documents with an `$unset` update to strip stale fields
  4. Use a projection so unknown fields are never fetched

Example fix

// before
const schema = new Schema({ name: String }, { strictRead: 'throw' });
const docs = await Model.find(); // old docs still contain `legacyField` -> StrictModeError

// after (acknowledge the field, or drop it silently)
const schema = new Schema(
  { name: String, legacyField: { type: Schema.Types.Mixed, select: false } },
  { strictRead: 'throw' }
);
// or simply: { strictRead: true }
Defensive patterns

Strategy: try-catch

Validate before calling

// Detect schema drift before hydrating raw objects
const known = new Set(Object.keys(MyModel.schema.paths).concat(['_id']));
const unknown = Object.keys(rawDoc).filter(k => !known.has(k));
if (unknown.length > 0) {
  // strip or log unknown keys before strictRead: 'throw' sees them
  for (const k of unknown) delete rawDoc[k];
}

Type guard

function isKnownField(model, key) {
  return key === '_id' || model.schema.path(key) != null;
}

Try / catch

try {
  const docs = await MyModel.find(query);
} catch (err) {
  if (err instanceof mongoose.Error.StrictModeError) {
    // stored data has fields the schema does not know; parse the path from err.message
    // then either add the path to the schema or relax strictRead to true
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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