{"record":{"id":"60779e719baec022","repo":"Automattic/mongoose","slug":"path-path-is-not-in-schema-strict-mode-is-t","errorCode":null,"errorMessage":"Path \"${path}\" is not in schema, strict mode is `true`, and upsert is `true`.","messagePattern":"Path \"(.+?)\" is not in schema, strict mode is `true`, and upsert is `true`\\.","errorType":"exception","errorClass":"StrictModeError","httpStatus":null,"severity":"error","filePath":"lib/cast.js","lineNumber":301,"sourceCode":"              }\n            }\n\n            _cast(value, numbertype, context);\n            continue;\n          }\n        }\n\n        if (schema.nested[path]) {\n          continue;\n        }\n\n        const strict = 'strict' in options ? options.strict : schema.options.strict;\n        const strictQuery = getStrictQuery(options, schema._userProvidedOptions, schema.options, context);\n        if (options.upsert && strict) {\n          if (strict === 'throw') {\n            throw new StrictModeError(path);\n          }\n          throw new StrictModeError(path, 'Path \"' + path + '\" is not in ' +\n            'schema, strict mode is `true`, and upsert is `true`.');\n        } if (strictQuery === 'throw') {\n          throw new StrictModeError(path, 'Path \"' + path + '\" is not in ' +\n            'schema and strictQuery is \\'throw\\'.');\n        } else if (strictQuery) {\n          delete obj[path];\n        }\n      } else if (val == null) {\n        continue;\n      } else if (utils.isPOJO(val)) {\n        any$conditionals = Object.keys(val).some(isOperator);\n\n        if (!any$conditionals) {\n          obj[path] = schematype.castForQuery(\n            null,\n            val,\n            context\n          );","sourceCodeStart":283,"sourceCodeEnd":319,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/cast.js#L283-L319","documentation":"With strict true (the default) and upsert true, mongoose treats schema-unknown paths as fatal rather than stripping them: cast() checks the upsert+strict combination first and throws StrictModeError with this message. A non-upsert update would silently delete the unknown path; the upsert makes it an error.","triggerScenarios":"Model.updateOne(filter, { unknownField: 1 }, { upsert: true }) on a default-strict schema; findOneAndUpdate(..., { upsert: true }) whose update contains client-added fields; $setOnInsert keys that are not modeled.","commonSituations":"Newer clients sending new fields before the schema is updated; payloads carrying metadata keys not modeled; sharing one object between save() and upsert code paths; renaming schema fields while old writers keep persisting the old name.","solutions":["Add the field to the schema","Strip unknown keys from the update before the call (pick only modeled fields)","Opt out per call: Model.updateOne(filter, update, { upsert: true, strict: false })","As a last resort set { strict: false } on the schema -- note this disables the guard for all writes"],"exampleFix":"// before\nawait Model.updateOne({ name: 'x' }, { name: 'x', extra: 1 }, { upsert: true }); // `extra` not in schema\n\n// after -- declare `extra` in the schema, or allow it for this call only:\nawait Model.updateOne({ name: 'x' }, { name: 'x', extra: 1 }, { upsert: true, strict: false });","handlingStrategy":"validation","validationCode":"function pickKnownPaths(Model, doc) {\n  const out = {};\n  for (const k of Object.keys(doc)) {\n    if (k in Model.schema.paths || k.startsWith('$')) out[k] = doc[k];\n  }\n  return out;\n}\nawait Model.updateOne(filter, pickKnownPaths(Model, update), { upsert: true });","typeGuard":null,"tryCatchPattern":"try {\n  await Model.updateOne(filter, update, { upsert: true });\n} catch (err) {\n  if (err.name === 'StrictModeError' && err.message.includes('upsert')) {\n    // either declare the path in the schema, strip it, or set strict: false for this call\n  }\n  throw err;\n}","preventionTips":["Map update payloads explicitly from transport DTOs to modeled fields","When introducing new client fields, ship the schema change first","Use strict: 'throw' in development to catch unknown paths early"],"tags":["mongoose","strict-mode","upsert","schema"],"backgroundTag":"strict-mode-violation","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}