stac-utils/stac-validator

Error validating Item with null geometry

TomAugspurger opened this issue · 8 comments

Apologies if this is a misunderstanding, but I think stac-validator incorrectly raises an error for items with null geometries, but valid bounding boxes.

An example, using pystac.

In [3]: import pystac, datetime

In [4]: item = pystac.Item('id', geometry=None, bbox=[1, 2, 3, 4], datetime=datetime.datetime(2000, 1, 1), properties={})

In [5]: item.validate()
---------------------------------------------------------------------------
ValidationError                           Traceback (most recent call last)
~/miniconda3/envs/stac-netcdf/lib/python3.8/site-packages/pystac/validation/stac_validator.py in validate_core(self, stac_dict, stac_object_type, stac_version, href)
    172         try:
--> 173             self._validate_from_uri(stac_dict, schema_uri)
    174             return schema_uri

~/miniconda3/envs/stac-netcdf/lib/python3.8/site-packages/pystac/validation/stac_validator.py in _validate_from_uri(self, stac_dict, schema_uri)
    133         schema, resolver = self.get_schema_from_uri(schema_uri)
--> 134         jsonschema.validate(instance=stac_dict, schema=schema, resolver=resolver)
    135         for uri in resolver.store:

~/miniconda3/envs/stac-netcdf/lib/python3.8/site-packages/jsonschema/validators.py in validate(instance, schema, cls, *args, **kwargs)
    933     if error is not None:
--> 934         raise error
    935

ValidationError: None is not of type 'object'

Failed validating 'type' in schema[0]:
    {'properties': {'bbox': {'items': {'type': 'number'},
                             'minItems': 4,
                             'type': 'array'},
                    'coordinates': {'items': {'type': 'number'},
                                    'minItems': 2,
                                    'type': 'array'},
                    'type': {'enum': ['Point'], 'type': 'string'}},
     'required': ['type', 'coordinates'],
     'title': 'GeoJSON Point',
     'type': 'object'}

On instance:
    None

The above exception was the direct cause of the following exception:

STACValidationError                       Traceback (most recent call last)
<ipython-input-5-ea5aa8dfeb4d> in <module>
----> 1 item.validate()

~/miniconda3/envs/stac-netcdf/lib/python3.8/site-packages/pystac/stac_object.py in validate(self)
    244             STACValidationError
    245         """
--> 246         return pystac.validation.validate(self)
    247
    248     def get_root(self):

~/miniconda3/envs/stac-netcdf/lib/python3.8/site-packages/pystac/validation/__init__.py in validate(stac_object)
     39         STACValidationError
     40     """
---> 41     validate_dict(stac_dict=stac_object.to_dict(),
     42                   stac_object_type=stac_object.STAC_OBJECT_TYPE,
     43                   stac_version=pystac.get_stac_version(),

~/miniconda3/envs/stac-netcdf/lib/python3.8/site-packages/pystac/validation/__init__.py in validate_dict(stac_dict, stac_object_type, stac_version, extensions, href)
     85         extensions = info.common_extensions
     86
---> 87     return RegisteredValidator.get_validator().validate(stac_dict, stac_object_type, stac_version,
     88                                                         extensions, href)
     89

~/miniconda3/envs/stac-netcdf/lib/python3.8/site-packages/pystac/validation/stac_validator.py in validate(self, stac_dict, stac_object_type, stac_version, extensions, href)
     77         # coordinate sequences for geometries).
     78         json_dict = json.loads(json.dumps(stac_dict))
---> 79         core_result = self.validate_core(json_dict, stac_object_type, stac_version, href)
     80         if core_result is not None:
     81             results.append(core_result)

~/miniconda3/envs/stac-netcdf/lib/python3.8/site-packages/pystac/validation/stac_validator.py in validate_core(self, stac_dict, stac_object_type, stac_version, href)
    176             msg = self._get_error_message(schema_uri, stac_object_type, None, href,
    177                                           stac_dict.get('id'))
--> 178             raise STACValidationError(msg, source=e) from e
    179
    180     def validate_extension(self,

STACValidationError: Validation failed for ITEM with ID id against schema at https://schemas.stacspec.org/v1.0.0-beta.2/item-spec/json-schema/item.json

According to https://github.com/radiantearth/stac-spec/blob/master/item-spec/item-spec.md, geometry is

REQUIRED. Defines the full footprint of the asset represented by this item, formatted according to RFC 7946, section 3.1. The footprint should be the default GeoJSON geometry, though additional geometries can be included. Coordinates are specified in Longitude/Latitude or Longitude/Latitude/Elevation based on WGS 84.

It's failing against the schema itself:
"oneOf": [
{
"type": "object",
"required": [
"geometry",
"bbox"
],
"properties": {
"geometry": {
"$ref": "https://geojson.org/schema/Geometry.json"
},
"bbox": {
"type": "array",
"oneOf": [
{
"minItems": 4,
"maxItems": 4
},
{
"minItems": 6,
"maxItems": 6
}
],
"items": {
"type": "number"
}
}
}
},
{
"type": "object",
"required": [
"geometry"
],
"properties": {
"geometry": {
"type": "null"
},
"bbox": {
"not": {}
}
}
}
]

@TomAugspurger are you using the newest version of stac-validator because it seems to be using 1.0.0-beta.2 as default in your example? Stac-validator is being used in pystac?

Whoops, my version of pystac-validator was up to date, but pystac was older. I've updated it so it's using 1.0.0 now.

Still seeing the same validator error:

ValidationError: None is not of type 'object'

Failed validating 'type' in schema[0]:
    {'properties': {'bbox': {'items': {'type': 'number'},
                             'minItems': 4,
                             'type': 'array'},
                    'coordinates': {'items': {'type': 'number'},
                                    'minItems': 2,
                                    'type': 'array'},
                    'type': {'enum': ['Point'], 'type': 'string'}},
     'required': ['type', 'coordinates'],
     'title': 'GeoJSON Point',
     'type': 'object'}

On instance:
    None

which, as you noted, is potentially an issue with the schema itself. I'll see if there's an issue reported already. Apologies for the false alarm.

@TomAugspurger I think the schema is saying that if geometry is null, there should be no bbox field but I could be completely wrong.

Yeah, it looks like that might be it.

And I see now that pystac might have its own validator, independent of stac-validator. I saw the path stac_validator but didn't realize it was a subpackage in pystac. So I got more than one thing wrong :)

All good :)

It fails in stac-validator too, just checked.

[
    {
        "version": "1.0.0",
        "path": "example.json",
        "schema": [
            "https://schemas.stacspec.org/v1.0.0/item-spec/json-schema/item.json"
        ],
        "valid_stac": false,
        "error_type": "ValidationError",
        "error_message": "None is not of type 'object'. Error is in geometry"
    }
]