1

I have the following JSON schema (testschema.json) that I am testing in Python3. I keep getting a validation error for property "alpha" and I have tried declaring the property in various ways to no avail.

{
    "id": "testschema",
    "$schema": "http://json-schema.org/draft-04/schema#",
    "description": "test schema",

    "type": "object",
    "properties": {


        "traffic_parameters": {

            "properties": {

                "test_type": {

                    "type": "string",
                    "enum": ["AA", "BB"]
                },

                "capacity": {

                    "oneOf": [
                        {
                            "properties": {

                                "min_percentage": {

                                    "type": "integer",
                                    "minimum" : 1,
                                    "maximum" : 150,
                                    "additionalProperties": false
                                },

                                "max_percentage": {

                                    "type": "integer",
                                    "minimum" : 1,
                                    "maximum" : 150,
                                    "additionalProperties": false
                                }
                            },

                            "additionalProperties": false
                        },

                        {
                            "properties": {

                                "percentage_range": {

                                    "type": "array",
                                    "minItems": 1,
                                    "maxItems": 10,
                                    "items": {

                                        "type": "integer"
                                    },

                                   "additionalProperties": false
                                }
                            },

                            "additionalProperties": false
                        }                    
                    ]
                }
            },

            "additionalProperties": false
        },


        "alpha": {

            "properties": {

                "beta": {

                    "oneOf": [
                        {
                            "properties": {

                                "AA": {

                                    "a":   [90, 95],
                                    "b":   [4, 8],
                                    "additionalProperties": false
                                }
                            },

                            "additionalProperties": false
                        },

                        {
                            "properties": {

                                "BB": {

                                    "a":   [100],
                                    "b":   [0],
                                    "c": [0],
                                    "additionalProperties": false
                                }
                            },

                            "additionalProperties": false
                        },

                        {
                            "properties": {

                                "CC": {

                                    "a":   [50],
                                    "b":   [50],
                                    "additionalProperties": false
                                }
                            },

                            "additionalProperties": false
                        },

                        {
                            "properties": {

                                "DD": {

                                    "a":   [0],
                                    "b":   [0],
                                    "c": [100],
                                    "additionalProperties": false  
                                }
                            },

                            "additionalProperties": false
                        }
                    ]
                }
            },

            "additionalProperties": false
        }
    },

    "required": ["traffic_parameters", "alpha"]
}

Here is the test JSON (test.json) that uses this schema.

{
    "traffic_parameters": {

        "test_type": "BB",

        "capacity": {

            "percentage_range": [1,2,3,4,5,6]
        }
     },

    "alpha": {

        "beta": "AA"
    }
}

When I validate this using the Python3 jsonschema module

with open("testschema.json") as schema_file:
    test_schema = json.load(schema_file)
schema_file.close()

with open("test.json") as json_file:
    test_json = json.load(json_file)
json_file.close()

validate(test_json, test_schema)

I get an error on the alpha property which is similar in structure to traffic_parameters which doesn't error.

jsonschema.exceptions.ValidationError: 'AA' is valid under each of {'properties': {'BB': ...

Here is the output

E
======================================================================
ERROR: test_valid__JSON_against_schema (__main__.SchemaTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test.py", line 35, in test_valid__JSON_against_schema
    validate(test_json, test_schema)
  File "/local/tools/PACKAGES/pyhton3/lib/python3.6/site-packages/jsonschema/validators.py", line 541, in validate
    cls(schema, *args, **kwargs).validate(instance)
  File "/local/tools/PACKAGES/pyhton3/lib/python3.6/site-packages/jsonschema/validators.py", line 130, in validate
    raise error
jsonschema.exceptions.ValidationError: 'AA' is valid under each of {'properties': {'BB': {'a': [100], 'b': [0], 'c': [0], 'additionalProperties': False}}, 'additionalProperties': False}, {'properties': {'CC': {'a': [50], 'b': [50], 'additionalProperties': False}}, 'additionalProperties': False}, {'properties': {'DD': {'a': [0], 'b': [0], 'c': [100], 'additionalProperties': False}}, 'additionalProperties': False}, {'properties': {'AA': {'a': [90, 95], 'b': [4, 8], 'additionalProperties': False}}, 'additionalProperties': False}

Failed validating 'oneOf' in schema['properties']['alpha']['properties']['beta']:
    {'oneOf': [{'additionalProperties': False,
                'properties': {'AA': {'a': [90, 95],
                                      'additionalProperties': False,
                                      'b': [4, 8]}}},
               {'additionalProperties': False,
                'properties': {'BB': {'a': [100],
                                      'additionalProperties': False,
                                      'b': [0],
                                      'c': [0]}}},
               {'additionalProperties': False,
                'properties': {'CC': {'a': [50],
                                      'additionalProperties': False,
                                      'b': [50]}}},
               {'additionalProperties': False,
                'properties': {'DD': {'a': [0],
                                      'additionalProperties': False,
                                      'b': [0],
                                      'c': [100]}}}]}

On instance['alpha']['beta']:
    'AA'

----------------------------------------------------------------------
Ran 1 test in 0.007s

FAILED (errors=1)

Does anyone know why this is and how to fix it?

Thanks.

Chris Nauroth
  • 9,614
  • 1
  • 35
  • 39
Dodomac
  • 194
  • 2
  • 17

1 Answers1

3

I'm going to shorten the schema to just enough to reproduce the validation failure:

{
    "id": "testschema",
    "$schema": "http://json-schema.org/draft-04/schema#",
    "description": "test schema",
    "type": "object",
    "properties": {
        "alpha": {
            "properties": {
                "beta": {
                    "oneOf": [
                        {
                            "properties": {
                                "AA": {
                                    "a":   [90, 95],
                                    "b":   [4, 8],
                                    "additionalProperties": false
                                }
                            },
                            "additionalProperties": false
                        },
                        {
                            "properties": {
                                "BB": {
                                    "a":   [100],
                                    "b":   [0],
                                    "c": [0],
                                    "additionalProperties": false
                                }
                            },
                            "additionalProperties": false
                        }
                    ]
                }
            },
            "additionalProperties": false
        }
    },
    "required": [ "alpha" ]
}

The error indicates failure to validate the oneOf constraint, because the "AA" validates successfully against every schema listed inside the oneOf, and oneOf demands that it must match one and only one.

Why does the "AA" validate against every schema? The root cause is that the schemas do not specify "type" information for every schema listed inside the oneOf. As explained here, if there is no "type" specified for a schema, then potentially any valid JSON of any type will match against that schema. To fix this, we need to add the missing "type" constraints.

From looking at the schema and JSON sample, I'm not certain what you want to achieve. The schema seems to be describing "AA", "BB", etc. as nested objects, but the JSON sample seems to show that "beta" just needs to be mapped to a string value like "AA".

If the JSON sample is the correct source of information, you could fix the problem with a schema like this.

schema = json.loads('''
{
    "id": "testschema",
    "$schema": "http://json-schema.org/draft-04/schema#",
    "description": "test schema",
    "type": "object",
    "properties": {
        "alpha": {
            "type": "object",
            "properties": {
                "beta": {
                    "type": "string",
                    "enum": [ "AA", "BB", "CC", "DD" ]
                }
            },
            "additionalProperties": false
        }
    },
    "required": [ "alpha" ]
}
''')

# valid
validate(json.loads('''
{
    "alpha": {
        "beta": "AA"
    }
}
'''), schema)

# valid
validate(json.loads('''
{
    "alpha": {
        "beta": "BB"
    }
}
'''), schema)

# invalid
validate(json.loads('''
{
    "alpha": {
        "beta": "ZZ"
    }
}
'''), schema)

Traceback (most recent call last):
  File "<stdin>", line 7, in <module>
  File "/Library/Python/2.7/site-packages/jsonschema/validators.py", line 541, in validate
    cls(schema, *args, **kwargs).validate(instance)
  File "/Library/Python/2.7/site-packages/jsonschema/validators.py", line 130, in validate
    raise error
jsonschema.exceptions.ValidationError: u'ZZ' is not one of [u'AA', u'BB', u'CC', u'DD']

Failed validating u'enum' in schema[u'properties'][u'alpha'][u'properties'][u'beta']:
    {u'enum': [u'AA', u'BB', u'CC', u'DD'], u'type': u'string'}

On instance[u'alpha'][u'beta']:
    u'ZZ'

OTOH, if your goal is for "AA", "BB", etc. to be sub-objects, then you can fix it by changing the schema to something like this.

schema = json.loads('''
{
    "id": "testschema",
    "$schema": "http://json-schema.org/draft-04/schema#",
    "description": "test schema",
    "type": "object",
    "properties": {
        "alpha": {
            "type": "object",
            "properties": {
                "beta": {
                    "oneOf": [
                        {
                            "type": "object",
                            "properties": {
                                "AA": {
                                    "type": "object",
                                    "properties": {
                                        "a": {
                                            "type": "array"
                                        }
                                    }
                                }
                            },
                            "additionalProperties": false
                        },
                        {
                            "type": "object",
                            "properties": {
                                "BB": {
                                    "type": "object",
                                    "properties": {
                                        "b": {
                                            "type": "array"
                                        }
                                    }
                                }
                            },
                            "additionalProperties": false
                        }
                    ]
                }
            },
            "additionalProperties": false
        }
    },
    "required": [ "alpha" ]
}
''')

# valid
validate(json.loads('''
{
    "alpha": {
        "beta": {
            "AA": {
                "a": [ 1 ]
            }
        }
    }
}
'''), schema)

# valid
validate(json.loads('''
{
    "alpha": {
        "beta": {
            "BB": {
                "b": [ 1 ]
            }
        }
    }
}
'''), schema)

# invalid
validate(json.loads('''
{
    "alpha": {
        "beta": {
            "ZZ": {
                "z": [ 1 ]
            }
        }
    }
}
'''), schema)
Traceback (most recent call last):
  File "<stdin>", line 11, in <module>
  File "/Library/Python/2.7/site-packages/jsonschema/validators.py", line 541, in validate
    cls(schema, *args, **kwargs).validate(instance)
  File "/Library/Python/2.7/site-packages/jsonschema/validators.py", line 130, in validate
    raise error
jsonschema.exceptions.ValidationError: {u'ZZ': {u'z': [1]}} is not valid under any of the given schemas

Failed validating u'oneOf' in schema[u'properties'][u'alpha'][u'properties'][u'beta']:
    {u'oneOf': [{u'additionalProperties': False,
                 u'properties': {u'AA': {u'properties': {u'a': {u'type': u'array'}},
                                         u'type': u'object'}},
                 u'type': u'object'},
                {u'additionalProperties': False,
                 u'properties': {u'BB': {u'properties': {u'b': {u'type': u'array'}},
                                         u'type': u'object'}},
                 u'type': u'object'}]}

On instance[u'alpha'][u'beta']:
    {u'ZZ': {u'z': [1]}}

# invalid
validate(json.loads('''
{
    "alpha": {
        "beta": {
            "AA": {
                "a": [ 1 ]
            },
            "BB": {
                "b": [ 1 ]
            }
        }
    }
}
'''), schema)

Traceback (most recent call last):
  File "<stdin>", line 14, in <module>
  File "/Library/Python/2.7/site-packages/jsonschema/validators.py", line 541, in validate
    cls(schema, *args, **kwargs).validate(instance)
  File "/Library/Python/2.7/site-packages/jsonschema/validators.py", line 130, in validate
    raise error
jsonschema.exceptions.ValidationError: {u'AA': {u'a': [1]}, u'BB': {u'b': [1]}} is not valid under any of the given schemas

Failed validating u'oneOf' in schema[u'properties'][u'alpha'][u'properties'][u'beta']:
    {u'oneOf': [{u'additionalProperties': False,
                 u'properties': {u'AA': {u'properties': {u'a': {u'type': u'array'}},
                                         u'type': u'object'}},
                 u'type': u'object'},
                {u'additionalProperties': False,
                 u'properties': {u'BB': {u'properties': {u'b': {u'type': u'array'}},
                                         u'type': u'object'}},
                 u'type': u'object'}]}

On instance[u'alpha'][u'beta']:
    {u'AA': {u'a': [1]}, u'BB': {u'b': [1]}}

Either way, the important thing is to make sure "type" information is specified where necessary.

Chris Nauroth
  • 9,614
  • 1
  • 35
  • 39
  • Thanks just what I needed. I also wanted to set the schema to certain fixed values for each of 'a' and 'b', so that the user may choose one set. I have done this with; "items": { "spot": [90, 95], "wide": [4, 8], "global": [0.2, 0.6] } I think my main confusion is what constitutes an object. But the link you provided helps, thanks again. – Dodomac Jul 24 '17 at 10:24
  • For example, if I had "number_of_scripts": { "type": "integer", "minimum" : 1, "maximum" : 200, "additionalProperties": false } would you advise adding "type": "object" and "properties" or will this suffice? – Dodomac Jul 24 '17 at 12:22
  • I have posted the second part of what I am trying to do as a separate question; https://stackoverflow.com/questions/45281533/how-do-you-assign-a-whole-object-along-with-its-properties-in-json – Dodomac Jul 24 '17 at 13:16