Skip to content

Incorrect validation of valid payload with valid schema #1362

Open
@DoDoENT

Description

@DoDoENT

I have a schema that heavily utilises $dynamicRef to inject parts of schema from other files.

Namely, here is the base schema:

base.json:

{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "$id": "base.json",
    "type": "object",
    "additionalProperties": false,
    "properties": {
        "orderNumber": {
            "type": "integer",
            "minimum": 0
        },
        "downstreamNumber": {
            "$dynamicRef": "#specialDownstreamNumber"
        },
        "schemaName": {
            "$dynamicRef": "#concreteName"
        },
        "schemaVersion": {
            "$dynamicRef": "#concreteVersion"
        },
        "timestamp": {
            "type": "integer"
        },
        "data": {
            "$dynamicRef": "#concreteData"
        }
    },
    "required": [
        "data",
        "orderNumber",
        "schemaName",
        "schemaVersion",
        "downstreamNumber",
        "timestamp"
    ],
    "$defs": {
        "name": {
            "const": "base",
            "$dynamicAnchor": "concreteName"
        },
        "version": {
            "const": "0.0.0",
            "$dynamicAnchor": "concreteVersion"
        },
        "data": {
            "not": true,
            "$dynamicAnchor": "concreteData"
        },
        "downstreamNumber": {
            "type": "integer",
            "minimum": 1,
            "$dynamicAnchor": "specialDownstreamNumber"
        }
    }
}

And here is the specific JSON that fills in the data for the base:

camera.json:

{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "$id": "camera.json",
    "$ref": "base.json",
    "$defs": {
        "name": {
            "const": "camera.info",
            "$dynamicAnchor": "concreteName"
        },
        "version": {
            "const": "1.0.0",
            "$dynamicAnchor": "concreteVersion"
        },
        "data": {
            "$dynamicAnchor": "concreteData",
            "type": "object",
            "additionalProperties": false,
            "properties": {
                "cameraFacing": {
                    "enum": [
                        "Front",
                        "Back"
                    ]
                },
                "cameraFrameSize": {
                    "$ref": "#/$defs/size"
                },
                "roi": {
                    "$ref": "#/$defs/size"
                },
                "viewPortAspectRatio": {
                    "type": "number"
                }
            },
            "required": [
                "cameraFacing",
                "cameraFrameSize",
                "roi",
                "viewPortAspectRatio"
            ]
        },
        "downstreamNumber": {
            "type": "integer",
            "minimum": 0,
            "$dynamicAnchor": "specialDownstreamNumber"
        },
        "size": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
                "width": {
                    "type": "integer"
                },
                "height": {
                    "type": "integer"
                }
            },
            "required": [
                "width",
                "height"
            ]
        }
    }
}

Here is the JSON that I'm trying to validate:

{
    "orderNumber": 4,
    "downstreamNumber": 1,
    "schemaVersion": "1.0.0",
    "schemaName": "camera.info",
    "timestamp": 1756525700,
    "data": {
        "cameraFacing": "Back",
        "cameraFrameSize": {
            "width": 3841,
            "height": 2161
        },
        "roi": {
            "width": 3840,
            "height": 1858
        },
        "viewPortAspectRatio": 2.066
    }
}

Here is how I'm doing the validation:

import json

from pathlib import Path

from jsonschema.validators import Draft202012Validator
from referencing import Registry, Resource


ROOT = Path(__file__).absolute().parent
SCHEMAS = ROOT / Path("schema")


def validate_file(validator: Draft202012Validator, file: Path):
    with open(file, "rt", encoding="utf-8") as f:
        instance = json.load(f)

    instance = json.loads(file.read_text())

    print(f"Validating {file}...")
    validator.validate(instance)


def retrieve_from_filesystem(uri: str):
    path = SCHEMAS / Path(uri)
    contents = json.loads(path.read_text())
    return Resource.from_contents(contents)


def main():
    registry = Registry(retrieve=retrieve_from_filesystem)

    schema_file = SCHEMAS / Path("camera.json")
    with open(schema_file, "rt", encoding="utf-8") as f:
        schema = json.load(f)

    validator = Draft202012Validator(
        schema,
        registry=registry
    )

    tests_path = ROOT / Path("payload")
    for file in tests_path.iterdir():
        validate_file(validator, file)


if __name__ == "__main__":
    main()

The validation fails with exception:

jsonschema.exceptions._WrappedReferencingError: PointerToNowhere: '/$defs/size' does not exist within {'$schema': 'https://json-schema.org/draft/2020-12/schema', '$id': 'base.json', 'type': 'object', 'additionalProperties': False, 'properties': {'orderNumber': {'type': 'integer', 'minimum': 0}, 'downstreamNumber': {'$dynamicRef': '#specialDownstreamNumber'}, 'schemaName': {'$dynamicRef': '#concreteName'}, 'schemaVersion': {'$dynamicRef': '#concreteVersion'}, 'timestamp': {'type': 'integer'}, 'data': {'$dynamicRef': '#concreteData'}}, 'required': ['data', 'orderNumber', 'schemaName', 'schemaVersion', 'downstreamNumber', 'timestamp'], '$defs': {'name': {'const': 'base', '$dynamicAnchor': 'concreteName'}, 'version': {'const': '0.0.0', '$dynamicAnchor': 'concreteVersion'}, 'data': {'not': True, '$dynamicAnchor': 'concreteData'}, 'downstreamNumber': {'type': 'integer', 'minimum': 1, '$dynamicAnchor': 'specialDownstreamNumber'}}}

Which is incorrect, as camera.json does contain /$defs/size. I've tried validating the payload with a different validator and it validates the payload successfully.

I don't see anything wrong with my schema definitions and boon has no problem validating the payload.

Is this a bug in jsonschema library or did I do something wrong and boon fails to detect it?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions