Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unevaluated properties and subschemas #1100

Closed
kvmw opened this issue Aug 6, 2024 · 4 comments
Closed

Unevaluated properties and subschemas #1100

kvmw opened this issue Aug 6, 2024 · 4 comments

Comments

@kvmw
Copy link

kvmw commented Aug 6, 2024

This bug is similar to #967 and #962 which are closed as fixed but the issue still is reproducible in v1.5.1

Library Version: 1.5.1.

Sample schema to reproduce the issue:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$defs": {
    "server-schema": {
      "type": "object",
      "properties": {
        "host": { "type": "string" },
        "port": { "type": "integer" }
      }
    }
  },
  "type": "object",
  "properties": {
    "server": {
      "$ref": "#/$defs/server-schema",
      "unevaluatedProperties": false
    }
  },
  "unevaluatedProperties": false
}

If I validate the following data:

{
  "server": {
    "host": "test",
    "port": 80,
    "bar": "another unknown property"
  },
  "foo": "unknown property"
}

I would get the following messages, which are expected and correct:

1) /server: property 'bar' is not evaluated and the schema does not allow unevaluated properties
2) : property 'foo' is not evaluated and the schema does not allow unevaluated properties

But If I change the data to contain, for example, invalid port:

{
  "server": {
    "host": "test",
    "port": "80 (string)",
    "bar": "another unknown property"
  },
  "foo": "unknown property"
}

The validation result would be:

1) /server/port: string found, integer expected
2) /server: property 'host' is not evaluated and the schema does not allow unevaluated properties
3) /server: property 'port' is not evaluated and the schema does not allow unevaluated properties
4) /server: property 'bar' is not evaluated and the schema does not allow unevaluated properties
5) : property 'foo' is not evaluated and the schema does not allow unevaluated properties

while 1, 4 and 5 are correct messages, 2 and 3 are not supposed to be there.

@justin-tay
Copy link
Contributor

justin-tay commented Aug 6, 2024

Unfortunately this is how the unevaluatedProperties keyword is defined in the specification. This keyword works based on annotations, and when a schema fails evaluation, the annotations get dropped.

You can compare the results with another implementation

From the specification: https://json-schema.org/draft/2020-12/json-schema-core#section-11-2

These instance items or properties may have been unsuccessfully evaluated against one or more adjacent keyword subschemas, such as when an assertion in a branch of an "anyOf" fails. Such failed evaluations are not considered to contribute to whether or not the item or property has been evaluated. Only successful evaluations are considered.

@kvmw
Copy link
Author

kvmw commented Aug 6, 2024

@justin-tay Thanks for the reply. This is very unfortunate because the error messages are confusing for the end user.

The reason I am putting the server-schema in the $ref is to avoid duplication in a json like following:

{
  "server": {
    "host": "test",
    "port": 80
  },
  "machines": [
     {
         "type": "server",
         "host": "test",
         "port": 80
     },
     {
        "type": "client",
        "name": "foo"
     }
   ]
}

As you see server can be either a field (server) or an item in another array (machines ). Of course I can duplicate the schema for both cases but server has many fields and duplication can cause other unwanted errors.

Is there any other way to achieve the same goal without using unevaluatedProperties ?

Here is a simplified version of my schema at the moment: https://www.jsonschemavalidator.net/s/CwNzBNQj

@justin-tay
Copy link
Contributor

You can attempt to try using additionalProperties but that doesn't work across a $ref which was the reason for unevaluatedProperties.

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$defs": {
    "server": {
      "type": "object",
      "properties": {
        "port": {
          "type": "integer"
        },
        "type": {
          "type": "string"
        }
      },
      "required": [
        "port"
      ],
      "additionalProperties": false
    },
    "client": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        },
        "type": {
          "type": "string"
        }
      },
      "required": [
        "name"
      ],
      "additionalProperties": false
    }
  },
  "type": "object",
  "properties": {
    "server": {
      "$ref": "#/$defs/server"
    },
    "client": {
      "$ref": "#/$defs/client"
    },
    "machines": {
      "type": "array",
      "items": {
        "allOf": [
          {
            "if": {
              "properties": {
                "type": {
                  "const": "server"
                }
              },
              "required": [
                "type"
              ]
            },
            "then": {
              "$ref": "#/$defs/server"
            }
          },
          {
            "if": {
              "properties": {
                "type": {
                  "const": "client"
                }
              },
              "required": [
                "type"
              ]
            },
            "then": {
              "$ref": "#/$defs/client"
            }
          }
        ]
      }
    }
  },
  "additionalProperties": false
}

@kvmw
Copy link
Author

kvmw commented Aug 7, 2024

This requires adding the type to both server and client which is not desired.

Thanks anyway. I am closing this issue.

@kvmw kvmw closed this as completed Aug 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants