Skip to content

Incorrect validation of valid payload with valid schema #1362

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?

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions