Skip to content

Fix find_additional_properties ignoring an empty patternProperties key - #1522

Open
vineethsaivs wants to merge 1 commit into
python-jsonschema:mainfrom
vineethsaivs:fix/additional-props-empty-pattern
Open

Fix find_additional_properties ignoring an empty patternProperties key#1522
vineethsaivs wants to merge 1 commit into
python-jsonschema:mainfrom
vineethsaivs:fix/additional-props-empty-pattern

Conversation

@vineethsaivs

Copy link
Copy Markdown

find_additional_properties in jsonschema/_utils.py collapses every patternProperties key into one regex with "|".join(...) and then guards it with if patterns:

patterns = "|".join(schema.get("patternProperties", {}))
for property in instance:
    if property not in properties:
        if patterns and re.search(patterns, property):
            continue
        yield property

"|".join maps both an empty patternProperties and {"": ...} to the same empty string, and if patterns then treats that empty (match-everything) pattern as absent. So an empty-string pattern key, which is a valid regex that matches every property, is silently dropped: its properties are reported as additional and validated against additionalProperties instead of the pattern subschema.

from jsonschema import Draft202012Validator as D

# "" matches every property, so patternProperties owns "x"; nothing is additional.
list(D({"additionalProperties": False,
        "patternProperties": {"": {"type": "integer"}}}).iter_errors({"x": 1}))
# before: ["'x' does not match any of the regexes: ''"]   (should be valid)

# The wrong subschema is applied, not just a spurious message:
list(D({"patternProperties": {"": {"type": "string"}},
        "additionalProperties": {"type": "integer"}}).iter_errors({"x": "hi"}))
# before: ["'hi' is not of type 'integer'"]   (should be valid: "x" matches "" -> string subschema)

The sibling helper find_evaluated_property_keys_by_schema (used for unevaluatedProperties) already iterates the patterns individually with re.search, so the two helpers disagree on the same schema. This change makes find_additional_properties do the same: iterate the patternProperties dict and skip a property if any pattern matches, which distinguishes "no patterns" (nothing to match) from an empty-string pattern (matches everything).

Added TestFindAdditionalProperties in jsonschema/tests/test_utils.py (fails before, passes after). The full JSON-Schema-Test-Suite still passes with no regressions.

find_additional_properties joined all patternProperties keys into a single
'|'.join(...) regex and guarded it with 'if patterns', which is falsy for an
empty string. An empty-string pattern key (a valid regex matching every
property) was therefore dropped, so its properties were wrongly treated as
additional and validated against additionalProperties instead of the pattern
subschema. The sibling find_evaluated_property_keys_by_schema already iterates
the patterns individually with re.search; mirror that here.
@Julian Julian added the Needs Test Upstream Issues that need to have a test added to https://github.com/json-schema-org/JSON-Schema-Test-Suite label Aug 1, 2026
@fallenmi

Copy link
Copy Markdown

Verified with Codex at exact head 2bd25c718550fcd37809719d658247721a207989.

On the exact base, both externally visible cases are RED: an empty patternProperties key incorrectly makes additionalProperties: false reject {"x": 1}, and a value matched by that empty pattern is incorrectly validated by the additionalProperties subschema. At this head, both schemas produce zero errors.

The one-commit diff also applies cleanly to current main b37f7be6dc7966a1f1a67557976041ffe0826cb3. The focused utility suite is 40/40, and the full no-extras suite ran 8,514 tests on both the exact head and the current-main integration (7,811 successes, 703 skips, no failures). Iterating the patterns individually also aligns this helper with the sibling evaluated-properties path while correctly distinguishing no patterns from the valid empty-string regex.

@vineethsaivs

Copy link
Copy Markdown
Author

Thank you for reproducing it independently, including running the full no-extras suite on both the head and a current-main integration.

To save a maintainer the re-check: the change is one commit touching find_additional_properties only, and it makes the helper iterate patternProperties individually so an empty pattern key stops being treated as "no patterns at all". That aligns it with the sibling evaluated-properties path, which already does this. Both externally visible symptoms are red on the base and green here: an empty patternProperties key made additionalProperties: false reject a perfectly valid instance, and a property matched by that empty pattern skipped the additionalProperties subschema entirely.

@Julian, happy to rebase or split this if you would like it in a different shape.

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

Labels

Needs Test Upstream Issues that need to have a test added to https://github.com/json-schema-org/JSON-Schema-Test-Suite

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants