ajv-validator / ajv-validator/ajv

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

オープン
#2,579 コメント 5 件 リアクション 0 件 担当者 0 名 GitHub で見る
主要言語
TypeScript
スター
14.8k
フォーク
1k
PR マージ指標
30日以内にマージされた PR はありません

説明

🔴 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.

コントリビューションガイド

コントリビューションガイドを開く

評価

この issue はまだ評価されていません。

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。