What version of Ajv are you using? Does the issue happen if you use the latest version?
4.11.3.
Ajv options object (see https://github.com/epoberezkin/ajv#options):
{
jsonPointers: true,
verbose: true
}
JSON Schema (please make it as small as possible to reproduce the issue):
{
"type": "object",
"oneOf": [
{
"properties": {
"foo": {
"type": "string",
"format": "ipv4"
}
},
"required": [ "foo" ],
"additionalProperties": false
},
{
"properties": {
"bar": {
"type": "string",
"format": "ipv4"
}
},
"required": [ "bar" ],
"additionalProperties": false
}
]
}
Data (please make it as small as possible to reproduce the issue):
{
"foo": "10.0.0.257"
}
Your code (please use options, schema and data as variables):
var options = {
jsonPointers: true,
verbose: true
};
var ajv = new Ajv(options);
var validate = ajv.compile(schema);
var valid = validate(data);
console.log(validate(data));
console.log(validate.errors);
https://runkit.com/krishnanms/58af9965e4edc300143368dd
Validation result, data AFTER validation, error messages:
[ { keyword: 'oneOf',
dataPath: '',
schemaPath: '#/oneOf',
params: {},
message: 'should match exactly one schema in oneOf',
schema: [ [Object], [Object] ],
parentSchema: { type: 'object', oneOf: [Object] },
data: { foo: '10.0.0.257' } } ]
What results did you expect?
The message shows 'should match exactly one schema in oneOf', while the schema validation failed due to an invalid format for the ip address, shouldn't this be the keyword and cause for the validation failure rather than oneOf?
Are you going to resolve the issue?
I am not sure I can.
@krishnanms "oneOf" requires the data to be valid against exactly one schema, unlike "anyOf" that requires that data is valid against any of the schemas (i.e. possibly valid against more than one schema).
In general, the approach to error reporting is that if all the errors are fixed then the data will be valid against the schema. That is not the case with oneOf though. In your case if Ajv were to return the errors from schemas inside oneOf it would return:
That's what Ajv would return if you used anyOf, by the way.
If you fix all these errors though (format of "foo" and add "bar") the data would still be invalid, because oneOf requires exactly one schema to be valid, not both.
That was the motivation to not report underlying errors from oneOf.
I will re-consider this decision, in the meanwhile you can:
In general it is always better to use "anyOf" in cases when schemas are mutually exclusive (both can't be valid at the same time), as in your case, and only use "oneOf" when you need to make sure that ONLY ONE schema is valid. "oneOf" will always validate data against ALL schemas, while "anyOf" always short circuits - as soon as the data is valid against some schema, validation of anyOf succeeds.
@epoberezkin Thanks for the detailed response. I was able to work around this, by setting allErrors: true and using the first error object in the array, which shows a message with invalid format. Not sure if this is the right way to go about it, but works.
@krishnanms interesting. I didn't realise it depends on allErrors option, I don't think it should. This option affects continuing validation after the first failure that determines the validation result, and oneOf keyword is the first such failure in both cases. So it should be made consistent.
If you decide to improve it please make PR to 5.0.0 branch.
Most helpful comment
@krishnanms "oneOf" requires the data to be valid against exactly one schema, unlike "anyOf" that requires that data is valid against any of the schemas (i.e. possibly valid against more than one schema).
In general, the approach to error reporting is that if all the errors are fixed then the data will be valid against the schema. That is not the case with oneOf though. In your case if Ajv were to return the errors from schemas inside oneOf it would return:
That's what Ajv would return if you used anyOf, by the way.
If you fix all these errors though (format of "foo" and add "bar") the data would still be invalid, because oneOf requires exactly one schema to be valid, not both.
That was the motivation to not report underlying errors from oneOf.
I will re-consider this decision, in the meanwhile you can:
In general it is always better to use "anyOf" in cases when schemas are mutually exclusive (both can't be valid at the same time), as in your case, and only use "oneOf" when you need to make sure that ONLY ONE schema is valid. "oneOf" will always validate data against ALL schemas, while "anyOf" always short circuits - as soon as the data is valid against some schema, validation of anyOf succeeds.