Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validator adds oneOf error to errors array even when schema is valid #185

Open
mdmower-csnw opened this issue Jul 16, 2024 · 0 comments
Open

Comments

@mdmower-csnw
Copy link

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)
      }
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant