MongoDB 6 vs 7 Schema Validation Changes

Teams planning a MongoDB 6.x to 7.x upgrade often ask which of their $jsonSchema validators need rewriting before cutover, and the measured answer this page gives is: none. It sits under Understanding MongoDB $jsonSchema Syntax within the broader MongoDB JSON Schema Validation Architecture, and its purpose is to separate what genuinely changed for validation authors across these two releases from what stayed byte-for-byte identical, so you can plan an upgrade with evidence rather than superstition. The short version is that $jsonSchema continues to implement JSON Schema Draft 4 semantics in both major versions, the structured failure detail that landed in 5.0 persists unchanged through 6 and 7, and validator syntax you author on 6.x deploys and behaves identically on 7.x. The reader outcome is a repeatable way to prove that portability on a throwaway collection before you touch a production replica set.

Operational Mechanics and Write-Path Impact

The validation subsystem did not fork between MongoDB 6.0 and 7.0. A $jsonSchema document is still compiled into a query predicate evaluated synchronously on the write path — insert, update, replace, findAndModify — with $out and $merge bypassing it on the destination exactly as before. The keyword surface is the same Draft 4 subset in both: bsonType, required, enum, pattern, properties, additionalProperties, patternProperties, the allOf/anyOf/oneOf/not combinators, and the numeric and array bounds. Neither release added a $jsonSchema keyword, and neither began honoring the later-draft keywords (if/then/else, $defs, unevaluatedProperties) that both continue to reject at collMod time. A schema that deploys on 6.0 deploys on 7.0, and a schema that fails on 6.0 fails identically on 7.0.

The meaningful usability improvement that authors care about — the structured errInfo.details.schemaRulesNotSatisfied object that names the exact failing keyword and JSON path — is not a 7.0 feature. It arrived in 5.0 and is carried forward unchanged through 6 and 7. If you are upgrading from 4.x, that structured detail is the real jump; if you are moving 6 to 7, it is already present on both sides and produces the same shape.

Validator portability across MongoDB 6.x and 7.x MongoDB 6.0.x and MongoDB 7.0.x both feed the same validator into an identical JSON Schema Draft 4 engine. Because the engine is unchanged, both versions produce the same rejection: WriteError code 121 carrying the structured schemaRulesNotSatisfied detail that was introduced in 5.0. The validator JSON you author is portable in both directions between the two releases. MongoDB 6.0.x validator JSON MongoDB 7.0.x validator JSON Draft 4 $jsonSchema engine identical in both releases code 121 on failure schemaRulesNotSatisfied portable portable Same validator, same engine, same failure shape — 6.x and 7.x are interchangeable for validation authors

Because there is no divergence in the validator itself, the entire feature comparison collapses into a table of “same” rows. The value of enumerating them is precisely that it lets you rule out a regression cause during an upgrade incident:

Validation feature MongoDB 6.x MongoDB 7.x
$jsonSchema draft semantics Draft 4 Draft 4
Structured errInfo.details.schemaRulesNotSatisfied Present (since 5.0) Present
validationLevel (strict / moderate / off) Supported Supported
validationAction (error / warn) Supported Supported
Failure code on rejected write WriteError code 121 WriteError code 121
Later-draft keywords (if/then, $defs, format) Rejected at collMod Rejected at collMod
collMod as metadata-only change Yes Yes
$out / $merge bypass the validator Yes Yes
bsonType extension (decimal, objectId, date) Supported Supported

What actually differs between 6.0 and 7.0 lives outside the validation contract — the query engine, storage internals, time-series enhancements, and the sharding surface all evolved — but none of it changes what your $jsonSchema accepts or rejects. Treat the validator as a stable artifact across the boundary and spend your upgrade budget on the things that did move.

Exact Diagnostic Fingerprints and Fast Resolution

The one upgrade-specific mechanic that does gate behavior is the featureCompatibilityVersion (FCV), and it is easy to misread as a validation problem. Moving a deployment to 7.0 requires the FCV to already be at 6.0; a binary upgrade with a lagging FCV can refuse newer commands. This never affects $jsonSchema evaluation — validators run the same at any FCV — but during a mixed-version window it is the first thing to confirm so you do not chase a phantom validation regression. Read the live server version and FCV directly:

// Ground-truth server version and feature compatibility, per node.
db.version()
// e.g. "7.0.11"
db.adminCommand({ getParameter: 1, featureCompatibilityVersion: 1 })
// => { featureCompatibilityVersion: { version: "7.0" }, ok: 1 }

The signatures below distinguish a real portability issue from noise during a 6 to 7 migration. Note that the first two are version-independent by design — they present identically on both releases, which is itself the diagnostic:

Signature Where it appears Root cause Resolution
code 121, "Document failed validation" Driver / client on both 6.x and 7.x The document genuinely violates the schema Read errInfo.details.schemaRulesNotSatisfied; the detail is identical across versions
Unknown $jsonSchema keyword: <name> at collMod mongod on both 6.x and 7.x Schema uses a later-draft keyword neither version honors Rewrite with Draft 4 combinators; this is not fixed by upgrading
OperationFailure code 13 (Unauthorized) on collMod Automation principal Missing collMod privilege, unrelated to version Grant dbAdmin; no version dependency
Newer command rejected during upgrade mongod mid-upgrade FCV still at 6.0 while binary is 7.0, or vice versa Advance FCV in the correct order; does not touch validators

The takeaway for triage: if a validator behaves differently after an upgrade, the cause is almost never the validation engine. Confirm the two collections carry byte-identical options.validator, validationLevel, and validationAction, and the discrepancy will resolve to configuration drift, not a version regression.

Step-by-Step Playbook

This sequence proves validator portability on a disposable namespace before you rely on it in production. It is safe to run against a 6.x node and a 7.x node — a staging replica of each, or the same throwaway collection observed before and after an in-place upgrade — and it never touches real data. The principle is the idempotent dry-run pattern used across collection-level validators: exercise the schema on a scratch collection, capture the exact rejection, then diff.

1. Create a throwaway collection with the candidate validator on 6.x. Attach the exact schema you run in production so the test is representative:

db.__v67_probe.drop()
db.createCollection("__v67_probe", {
  validator: { $jsonSchema: {
    bsonType: "object",
    required: ["tenant_id", "currency"],
    properties: {
      tenant_id: { bsonType: "string", minLength: 1 },
      currency: { bsonType: "string", pattern: "^[A-Z]{3}$" }
    },
    additionalProperties: false
  }},
  validationLevel: "strict",
  validationAction: "error"
})
// Expected output: { ok: 1 }

2. Capture the applied options and a known-bad rejection. Record both the stored validator and the structured failure detail — these are the artifacts you will compare after the upgrade:

db.getCollectionInfos({ name: "__v67_probe" })[0].options
// => { validator: {...}, validationLevel: "strict", validationAction: "error" }

try {
  db.__v67_probe.insertOne({ tenant_id: "acme", currency: "usd" })  // lowercase fails pattern
} catch (e) {
  printjson(e.errInfo.details.schemaRulesNotSatisfied)
  // records the exact failing keyword + path, e.g. pattern on "currency"
}

3. Recreate the identical probe on 7.x and replay. After the upgrade (or on the 7.x staging node), repeat steps 1 and 2 verbatim. A driver-side script makes the comparison mechanical rather than visual:

from pymongo import MongoClient
from pymongo.errors import WriteError

client = MongoClient("mongodb://localhost:27017")  # point at the 7.x node
db = client.staging

def probe_options_and_failure(schema: dict) -> tuple[dict, list]:
    db.drop_collection("__v67_probe")
    db.create_collection("__v67_probe", validator={"$jsonSchema": schema},
                         validationLevel="strict", validationAction="error")
    opts = db.command("listCollections", filter={"name": "__v67_probe"}
                      )["cursor"]["firstBatch"][0]["options"]
    try:
        db.__v67_probe.insert_one({"tenant_id": "acme", "currency": "usd"})
        rules = []  # unexpected: the bad doc was accepted
    except WriteError as exc:
        rules = exc.details["errInfo"]["details"]["schemaRulesNotSatisfied"]
    return opts, rules

4. Diff the two captures. The options objects and the schemaRulesNotSatisfied structures must match between versions. If they do, the validator is proven portable and needs no rewrite:

db.__v67_probe.drop()   // clean up the disposable namespace
// Expected: identical options + identical failing-keyword path on 6.x and 7.x

Failure Modes & Rollback

Each step has a bounded, low-risk failure mode because nothing here writes to a production collection:

  • The probe schema is rejected on one version but not the other (step 1 or 3). This should never happen for a genuine Draft 4 schema. If it does, the schema contains a later-draft keyword that one path tolerated only because it was never actually deployed — inspect the collMod/createCollection error text for Unknown $jsonSchema keyword and rewrite with combinators. Upgrading does not fix it.
  • options differ between captures (step 4). The cause is configuration drift, not the engine — a differing validationLevel or a stale validator on one node. Reapply the intended validator with collMod so both nodes carry identical metadata.
  • FCV blocks a command mid-upgrade (step 3). Confirm the FCV with the diagnostic above and advance it in order; this is an upgrade-sequencing issue that is independent of any validator.

There is no data rollback to perform — the probe is a disposable namespace, so recovery is simply db.__v67_probe.drop(), which is instantaneous. For the production collections themselves, the upgrade does not modify validators, so no validator rollback is required; if you separately changed a validator during the maintenance window, revert it with a single metadata-only collMod that restores the prior options, with a time-to-recover of the replication lag of your slowest secondary. Version the schema artifact you deploy through schema versioning strategies for NoSQL so “the validator we ran on 6.x” is a retrievable, auditable object rather than a memory.

Frequently Asked Questions

Do I need to rewrite my $jsonSchema validators when upgrading from MongoDB 6 to 7?

No. Both 6.x and 7.x implement JSON Schema Draft 4 semantics with the same keyword surface, the same validationLevel and validationAction dials, and the same code 121 rejection carrying schemaRulesNotSatisfied. A validator authored and deployed on 6.x behaves identically on 7.x, and the reverse is also true. The disposable-collection probe in the playbook proves this for your specific schema before cutover.

Did MongoDB 7.0 add any new schema validation keywords or change the failure detail?

No new $jsonSchema keywords were added in 7.0, and the later-draft keywords such as if/then/else and $defs are still rejected at collMod time exactly as in 6.x. The structured errInfo.details.schemaRulesNotSatisfied object is unchanged — it was introduced in 5.0 and is carried forward through 6 and 7 with the same shape, so downstream error parsers need no update.

Does featureCompatibilityVersion affect how a validator behaves?

No. FCV gates which server commands and storage features are available during and after an upgrade; it does not change how $jsonSchema evaluates a write. Validators enforce identically at any supported FCV. FCV matters to the upgrade sequence — 7.0 expects the FCV to already be at 6.0 — but a rejection you see under one FCV you will see under the other, because the validation engine is the same code path.

For the authoritative operator behavior referenced above, consult the official MongoDB schema-validation documentation.