Bug when a schema has a nullable AllOf ref
knivets opened this issue · 8 comments
Hey! I have a weird issue that happens with refs that are nullable. I have the following schema:
"GroupWithRecentMessage": {
"type": "object",
"properties": {
"uid": {
"type": "string",
"format": "uuid",
"readOnly": true
},
"recent_message": {
"allOf": [
{
"$ref": "#/components/schemas/Message"
}
],
"readOnly": true,
"nullable": true
}
}
}
Essentially what I try to express is that recent_message can be either null or an object of type Message.
When I run a validator it raises an exception:
openapi_core.unmarshalling.schemas.exceptions.InvalidSchemaValue: Value {
'results': [{'uid': '018a8f79-5098-478b-a77e-2adb685a1ea5', 'recent_message': None}]
} not valid for schema of type object: (<ValidationError: 'None for not nullable'>
After debugging the issue I have been able to find the root cause. I think the main reason why it happens is that openapi-schema-validator adds a "nullable": false to each ref. So the actual schema that ends being used is the following:
{'nullable': False,
'properties': {'recent_message': {'allOf': [{'$ref': '#/components/schemas/Message',
'nullable': False, # <---- this is what triggers the wrong error
'x-scope': ['',
'#/components/schemas/GroupWithRecentMessage']}],
'nullable': True,
'readOnly': True},
'uid': {'format': 'uuid',
'nullable': False,
'readOnly': True,
'type': 'string'}},
'required': ['recent_message',
'uid'],
'type': 'object'}
How can I fix this issue?
Thanks!
I have also bumped into this issue. I believe that these lines are incorrect and should be removed:
This is for a number of reasons, all of which have affected me:
- OpenAPI 3.0.x should ignore siblings of
$ref(1) - OpenAPI 3.0.x needs special hacks for
nullablewithenum(1, 2, 3) - This breaks
nullableset toTruealongsideallOf/anyOf/oneOf. (This is your case @knivets.)
The comment # append defaults to trigger validator (i.e. nullable) doesn't seem to make sense as validation seems to work perfectly fine without it. Perhaps @p1c2u can shed some light on why this is/was necessary?
This shouldn't be an issue with OpenAPI 3.1.x when it is supported as null is allowed as a type.
I have used the following workaround which may help:
from openapi_core.unmarshalling.schemas.enums import UnmarshalContext
from openapi_core.unmarshalling.schemas.factories import SchemaUnmarshallersFactory
from openapi_core.validation.response.validators import ResponseValidator
from openapi_schema_validator import OAS30Validator
class FixedOAS30Validator(OAS30Validator):
def iter_errors(self, instance, _schema=None):
# Use the implementation of .iter_errors() from the parent.
return super(OAS30Validator, self).iter_errors(instance, _schema)
class FixedSchemaUnmarshallersFactory(SchemaUnmarshallersFactory):
def get_validator(self, schema):
kwargs = {"resolver": self.resolver, "format_checker": self.format_checker}
if self.context is not None:
kwargs[self.CONTEXT_VALIDATION[self.context]] = True
with schema.open() as schema_dict:
return FixedOAS30Validator(schema_dict, **kwargs)
class FixedResponseValidator(ResponseValidator):
@property
def schema_unmarshallers_factory(self):
return FixedSchemaUnmarshallersFactory(
self.spec.accessor.dereferencer.resolver_manager.resolver,
self.format_checker,
self.custom_formatters,
context=UnmarshalContext.RESPONSE,
)We are experiencing the same issue. As the previous comment stated: Perhaps @p1c2u can shed some light on why this is/was necessary?
That's exactly what comment says to trigger nullable validator.
The comment # append defaults to trigger validator (i.e. nullable) doesn't seem to make sense as validation seems to work perfectly fine without it.
It can work fine if you define nullable param explicitly.
For schema without nullable defined (default is False) if you pass None value it won't raise validation error - which is incorrect. You can try to remove these lines and run tests.
Same here, can't reproduce the issue. @claeyswo which jsonschema version you use and do you have any example of the issue?
3.0, but by adding nullable to every item the problem was solved. By switching the nullable om some_id in the example below we get the desired effect.
schema = {
"$ref": "#/components/schemas/TestSchema",
"components": {
"schemas": {
"IntegerString": {
"anyOf": [
{"type": "integer", "nullable": True},
{"type": "string", "nullable": True},
],
"nullable": True,
},
"TestSchema": {
"type": "object",
"properties": {
"some_id": {
"$ref": "#/components/schemas/IntegerString",
"nullable": True,
}
},
},
}
},
}attribute:
nullable: true
$ref: '#/components/Example'
attribute:
oneOf:
- type: "null"
- $ref: '#/components/Example'
Neither work, any update on a fix for this?
There were ambiguities in the semantics of nullable in OAS 3.0.0-2 More about the issue can be found in the following proposal. OAS 3.0.3 clarified the definition so it can be implemented properly. There shouldn't be any major backward compatibility issues.