Automattic/mongoose · error · StrictModeError
Path `${path}` is immutable and strict mode is set to throw.
Error message
Path `${path}` is immutable and strict mode is set to throw. What it means
Document-level counterpart of the update-side immutable guard: assigning to a path declared immutable: true on a persisted (non-new) document is normally silently ignored (the previous value is kept). If the document's strict mode is 'throw' and the new value differs from the stored prior value, the immutable setter throws this StrictModeError instead. Immutable paths are write-once: set at creation, unchangeable on loaded documents.
Source
Thrown at lib/helpers/schematype/handleImmutable.js:44
if (this.isNew) {
return v;
}
if (options?.overwriteImmutable) {
return v;
}
const _immutable = typeof immutable === 'function' ?
immutable.call(this, this) :
immutable;
if (!_immutable) {
return v;
}
const _value = this.$__.priorDoc != null ?
this.$__.priorDoc.$__getValue(path) :
this.$__getValue(path);
if (this.$__.strictMode === 'throw' && v !== _value) {
throw new StrictModeError(path, 'Path `' + path + '` is immutable ' +
'and strict mode is set to throw.', true);
}
return _value;
};
}
View on GitHub (pinned to 49cdab0136)
Solutions
- Skip assignment to immutable paths when updating existing documents (check doc.isNew or the schema path's immutable option)
- If the field must be editable, remove immutable: true or make it conditional with a function (immutable: function() { ... })
- Force an intentional change through the query layer: Model.updateOne({ _id: doc._id }, { $set: { name: 'new' } }, { overwriteImmutable: true })
- Re-create the document instead of mutating an immutable field on a loaded one
Example fix
// before const user = await User.findById(id); user.email = req.body.email; // email is immutable, strict: 'throw' -> throws await user.save(); // after const user = await User.findById(id); user.displayName = req.body.displayName; // mutable await user.save();
Defensive patterns
Strategy: validation
Validate before calling
// Skip assignment of immutable paths on loaded documents
function assignMutable(doc, patch) {
const schema = doc.schema;
for (const [k, v] of Object.entries(patch)) {
if (!doc.isNew && schema.path(k)?.options?.immutable) continue;
doc.set(k, v);
}
} Type guard
const isImmutablePath = (schema, path) => Boolean(schema.path(path)?.options?.immutable);
Try / catch
try {
doc.set('name', value);
await doc.save();
} catch (err) {
if (err instanceof mongoose.Error.StrictModeError && /immutable/.test(err.message)) {
// reject the edit or route through Model.updateOne(..., { overwriteImmutable: true })
} else throw err;
} Prevention
- Map PATCH endpoints to explicit mutable field lists instead of assigning whole bodies
- Make immutability conditional (immutable: () => cond) when a field is editable in some flows
- Test edit flows against strict:'throw' schemas in CI so violations surface early
When it happens
Trigger: doc.name = 'new' or doc.set('name', 'new') where the schema declares name: { type: String, immutable: true }, the document was loaded from the DB (isNew false, priorDoc exists), and the schema (or document) uses strict: 'throw'.
Common situations: Generic form handlers that assign every submitted field onto a loaded document; schemas hardened with strict:'throw'; write-once fields like username, email, or tenant id edited after onboarding; bulk import scripts mutating loaded docs.
Related errors
- Field ${fullPath} is immutable and strict = 'throw'
- Aggregate `near()` argument must have a `near` property
- Aggregate `near()` argument has invalid coordinates, got "${
- Field `${path}` is not in schema and strict mode is set to t
- Path "${path}" is not in schema, strict mode is `true`, and
AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21).
Data as JSON: /api/errors/9353aa690e868950.
Report an issue: GitHub.