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

compileAsync does not loadSchema a schema that is $ref’d by a oneOf with a discriminator #2427

Labels

Comments

@yonran
Copy link
Contributor

yonran commented May 7, 2024

What version of Ajv are you using? Does the issue happen if you use the latest version?

latest (8.13.0)

Ajv options object

const options = {
  discriminator: true,
  async loadSchema(url) {
    console.log('loadSchema', url)
    const name = url.substring("scheme://".length)
    return schemas[name]
  },
};

JSON Schema

const schemas = {
  main: {
    type: "object",
    discriminator: {propertyName: "foo"},
    required: ["foo"],
    oneOf: [
      {
        $ref: "scheme://schema1",
      },
      {
        $ref: "scheme://schema2",
      },
    ],
  },
  schema1: {
    type: "object",
    properties: {
      foo: {const: "x"},
    },
  },
  schema2: {
    type: "object",
    properties: {
      foo: {enum: ["y", "z"]},
    },
  },
};

Sample data

{"foo": "x"}

Your code

const Ajv = require("ajv");
const ajv = new Ajv(options);
// If you uncomment this, then there is no error
// Object.entries(schemas).forEach(([id, schema]) => {
//   ajv.addSchema(schema, 'scheme://' + id)
// })
async function main() {
  const validate = await ajv.compileAsync(schemas.main)
  validate(data)
}
main().catch((err) => console.log(err))

Validation result, data AFTER validation, error messages

Error: discriminator: oneOf subschemas (or referenced schemas) must have "properties/foo"

What results did you expect?
No error

Are you going to resolve the issue?
Maybe if it is easy

Notes:

  • If you call ajv.addSchema (i.e., uncomment the commented code), then the error goes away. Therefore, it is the resolving of the $ref that is the issue

  • When discriminator: true, then loadSchema is not called.

  • But if you set discriminator: false and remove the discriminator from schema.main, then loadSchema is called.

    loadSchema scheme://schema1
    loadSchema scheme://schema2
    

My guess is that lib/vocabularies/discriminator/index.ts’s getMapping() needs to throw new MissingRefError so that _compileAsync can catch the error and load the missing schemas.

@jasoniangreen
Copy link
Collaborator

jasoniangreen commented May 7, 2024

Hi @yonran thanks for raising this, I have setup your example and it does look like it could be a bug. Since you responded "Maybe if it is easy" I'll ask if you would like to have a go at submitting a PR? Either way I will look into this and consider it a bug for now.

yonran added a commit to yonran/ajv that referenced this issue May 10, 2024
Make the discriminator code generation throw MissingRefError when the $ref does not synchronously resolve so that compileAsync can loadSchema and retry.
jasoniangreen pushed a commit that referenced this issue May 12, 2024
Make the discriminator code generation throw MissingRefError when the $ref does not synchronously resolve so that compileAsync can loadSchema and retry.
@mathieubathalon
Copy link

lib/commands/query.js

@mathieubathalon
Copy link

``

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment