ajv-validator / ajv-validator/ajv

oneOf incorrectly tracks evaluated properties for unevaluatedProperties (Draft 2020-12)

Offen
#2,579 5 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
Vorherrschende Sprache
TypeScript
Sterne
14.8k
Forks
1k
PR-Merge-Kennzahlen
Keine gemergten PRs in 30 T.

Beschreibung

🔴 Summary

When using oneOf together with unevaluatedProperties (Draft 2020-12), Ajv only merges evaluation information from the subschema that passes validation.
Properties (or items) that are processed by oneOf branches which fail validation are not recorded as evaluated, which can cause unevaluatedProperties: false to incorrectly reject valid instances.

📜 Spec reference

JSON Schema Draft 2020-12, §6.5.3.2.2 (Evaluation of instance locations):

Instance locations are considered evaluated when they are processed by an applicable keyword, regardless of whether validation of that keyword succeeds or fails.

Under this model, evaluation is tied to processing, not to overall subschema validity in oneOf.

📍 Location in code
lib/vocabularies/applicator/oneOf.ts

Specifically, cxt.mergeEvaluated(...) is currently called only when schValid === true, so evaluated locations from failing oneOf branches are dropped.

🧪 Minimal reproduction

Schema (Draft 2020-12):

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"oneOf": [
{
"properties": { "a": { "type": "string" } },
"required": ["a", "x"]
},
{
"properties": { "b": { "type": "number" } },
"required": ["b"]
}
],
"unevaluatedProperties": false
}

Instance:

{ "a": "test", "b": 42 }

❌ Current behavior

Subschema 0 evaluates property "a" but fails overall (missing "x").

Subschema 1 evaluates property "b" and passes.

Ajv merges evaluated properties only from the passing subschema.

Property "a" is treated as unevaluated, causing a validation failure.

✅ Expected behavior

Both "a" and "b" should be considered evaluated, since they were processed by applicable keywords in oneOf subschemas.
The instance should validate successfully, and only truly unevaluated properties (e.g. "c") should be rejected.

💥 Impact

Causes false negatives when combining oneOf with unevaluatedProperties.

Affects common real-world patterns (union-like object schemas in APIs).

Violates Draft 2020-12 evaluation semantics.

🔧 Suggested fix (high-level)

Merge evaluated properties/items from all evaluated oneOf subschemas, regardless of validation outcome, while keeping the existing oneOf requirement that exactly one subschema must pass.
Since mergeEvaluated is already gated by opts.unevaluated, this should not affect drafts or configurations where unevaluated tracking is disabled.

📝 Notes

I have a local patch and regression tests that address this issue and am happy to open a PR if the approach above aligns with Ajv’s expectations.

Beitragsleitfaden

Beitragsleitfaden öffnen

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.