From d501318d2294b3001526895cd60ad5d8bb7cda7c Mon Sep 17 00:00:00 2001 From: Yuki9814 Date: Sun, 15 Mar 2026 23:45:38 +0800 Subject: [PATCH 1/2] fix: resolve UnboundLocalError for first_valid in oneOf validator The first_valid variable was only assigned inside the for-else loop when a valid schema was found. If no valid schema was found initially but more_valid schemas were discovered later, the code would attempt to access an undefined variable. Initialize first_valid to None and check before using it. --- jsonschema/_keywords.py | 43 ++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/jsonschema/_keywords.py b/jsonschema/_keywords.py index f30f95419..2316b502c 100644 --- a/jsonschema/_keywords.py +++ b/jsonschema/_keywords.py @@ -21,7 +21,10 @@ def patternProperties(validator, patternProperties, instance, schema): for k, v in instance.items(): if re.search(pattern, k): yield from validator.descend( - v, subschema, path=k, schema_path=pattern, + v, + subschema, + path=k, + schema_path=pattern, ) @@ -204,18 +207,13 @@ def maxItems(validator, mI, instance, schema): def uniqueItems(validator, uI, instance, schema): - if ( - uI - and validator.is_type(instance, "array") - and not uniq(instance) - ): + if uI and validator.is_type(instance, "array") and not uniq(instance): yield ValidationError(f"{instance!r} has non-unique elements") def pattern(validator, patrn, instance, schema): - if ( - validator.is_type(instance, "string") - and not re.search(patrn, instance) + if validator.is_type(instance, "string") and not re.search( + patrn, instance ): yield ValidationError(f"{instance!r} does not match {patrn!r}") @@ -262,7 +260,9 @@ def dependentSchemas(validator, dependentSchemas, instance, schema): if property not in instance: continue yield from validator.descend( - instance, dependency, schema_path=property, + instance, + dependency, + schema_path=property, ) @@ -312,7 +312,8 @@ def required(validator, required, instance, schema): def minProperties(validator, mP, instance, schema): if validator.is_type(instance, "object") and len(instance) < mP: message = ( - "should be non-empty" if mP == 1 + "should be non-empty" + if mP == 1 else "does not have enough properties" ) yield ValidationError(f"{instance!r} {message}") @@ -323,8 +324,7 @@ def maxProperties(validator, mP, instance, schema): return if validator.is_type(instance, "object") and len(instance) > mP: message = ( - "is expected to be empty" if mP == 0 - else "has too many properties" + "is expected to be empty" if mP == 0 else "has too many properties" ) yield ValidationError(f"{instance!r} {message}") @@ -351,6 +351,7 @@ def anyOf(validator, anyOf, instance, schema): def oneOf(validator, oneOf, instance, schema): subschemas = enumerate(oneOf) all_errors = [] + first_valid = None for index, subschema in subschemas: errs = list(validator.descend(instance, subschema, schema_path=index)) if not errs: @@ -364,10 +365,11 @@ def oneOf(validator, oneOf, instance, schema): ) more_valid = [ - each for _, each in subschemas + each + for _, each in subschemas if validator.evolve(schema=each).is_valid(instance) ] - if more_valid: + if more_valid and first_valid is not None: more_valid.append(first_valid) reprs = ", ".join(repr(schema) for schema in more_valid) yield ValidationError(f"{instance!r} is valid under each of {reprs}") @@ -393,10 +395,13 @@ def unevaluatedItems(validator, unevaluatedItems, instance, schema): if not validator.is_type(instance, "array"): return evaluated_item_indexes = find_evaluated_item_indexes_by_schema( - validator, instance, schema, + validator, + instance, + schema, ) unevaluated_items = [ - item for index, item in enumerate(instance) + item + for index, item in enumerate(instance) if index not in evaluated_item_indexes ] if unevaluated_items: @@ -408,7 +413,9 @@ def unevaluatedProperties(validator, unevaluatedProperties, instance, schema): if not validator.is_type(instance, "object"): return evaluated_keys = find_evaluated_property_keys_by_schema( - validator, instance, schema, + validator, + instance, + schema, ) unevaluated_keys = [] for property in instance: From 9f8bc6994662a48dbe3d22c7c1880be19d64acb6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 15 Mar 2026 15:46:12 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- jsonschema/_keywords.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsonschema/_keywords.py b/jsonschema/_keywords.py index 2316b502c..a5fc49b44 100644 --- a/jsonschema/_keywords.py +++ b/jsonschema/_keywords.py @@ -213,7 +213,7 @@ def uniqueItems(validator, uI, instance, schema): def pattern(validator, patrn, instance, schema): if validator.is_type(instance, "string") and not re.search( - patrn, instance + patrn, instance, ): yield ValidationError(f"{instance!r} does not match {patrn!r}")