When validating a schema that includes oneOf with a ref, an error is pushed to the final validator.errors array even if the oneOf schema passes validation. The overall validation result (true/false) is correct, but when validation fails, one of the errors is not correct.
Steps to reproduce
sample.schema.json
{
"type": "object",
"$defs": {
"level": {
"enum": ["error", "info"]
}
},
"properties": {
"some_name": { "type": "string" },
"some_level": {
"oneOf": [{ "const": null }, { "$ref": "#/$defs/level" }]
}
}
}
sample.json
{
"some_name": 3,
"some_level": null
}
main.js
import { validator } from "@exodus/schemasafe";
import { readFileSync } from "fs";
const schema = JSON.parse(readFileSync("sample.schema.json", "utf-8"));
const sample = JSON.parse(readFileSync("sample.json", "utf-8"));
const validate = validator(schema, { includeErrors: true, allErrors: true });
if (!validate(sample)) {
console.error(validate.errors);
} else {
console.log("config ok");
}
Output
some_level is reported to have an error even though it doesn't.
[
{
keywordLocation: '#/properties/some_name/type',
instanceLocation: '#/some_name'
},
{
keywordLocation: '#/properties/some_level/oneOf/1/$ref/enum',
instanceLocation: '#/some_level'
}
]
Notes
When I inspect the compiled validator, it looks like the error from the failed $ref is pushed onto validate.errors instead of being held in suberr1 to determine later whether it should land in validate.errors depending on the overall oneOf status. See comments in code snippet below:
if ("some_level" in data && hasOwn(data, "some_level")) {
let passes0 = 0
let suberr0 = null
const sub0 = (() => {
let errorCount = 0
if (!(data.some_level === null)) {
if (suberr0 === null) suberr0 = []
suberr0.push({ keywordLocation: "#/properties/some_level/oneOf/0/const", instanceLocation: "#/some_level" })
errorCount++
}
return errorCount === 0
})()
if (sub0) passes0++
const sub1 = (() => {
let errorCount = 0
const err0 = validate.errors
const res0 = ref1(data.some_level)
const suberr1 = ref1.errors
validate.errors = err0
if (!res0) {
if (validate.errors === null) validate.errors = []
/** START: Possible reason for issue */
validate.errors.push(...suberr1.map(e => errorMerge(e, "#/properties/some_level/oneOf/1/$ref", "#/some_level")))
/** END: Possible reason for issue */
errorCount++
}
return errorCount === 0
})()
if (sub1) passes0++
if (passes0 !== 1) {
if (validate.errors === null) validate.errors = []
validate.errors.push({ keywordLocation: "#/properties/some_level/oneOf", instanceLocation: "#/some_level" })
errorCount++
}
if (passes0 === 0) {
if (suberr0) validate.errors.push(...suberr0)
}
}
When validating a schema that includes
oneOfwith aref, an error is pushed to the finalvalidator.errorsarray even if theoneOfschema passes validation. The overall validation result (true/false) is correct, but when validation fails, one of the errors is not correct.Steps to reproduce
sample.schema.json
{ "type": "object", "$defs": { "level": { "enum": ["error", "info"] } }, "properties": { "some_name": { "type": "string" }, "some_level": { "oneOf": [{ "const": null }, { "$ref": "#/$defs/level" }] } } }sample.json
{ "some_name": 3, "some_level": null }main.js
Output
some_levelis reported to have an error even though it doesn't.Notes
When I inspect the compiled validator, it looks like the error from the failed
$refis pushed ontovalidate.errorsinstead of being held insuberr1to determine later whether it should land invalidate.errorsdepending on the overalloneOfstatus. See comments in code snippet below: