From d394926beda5cc7c2c5304ae173efdf0df47b986 Mon Sep 17 00:00:00 2001 From: p1c2u Date: Fri, 3 Apr 2026 00:06:58 +0100 Subject: [PATCH] Fix unstable error message for additional properties --- .../validation/schemas/_validators.py | 2 +- ...st_additional_properties_default_policy.py | 37 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/openapi_core/validation/schemas/_validators.py b/openapi_core/validation/schemas/_validators.py index 8fd5f753..f1fe8fc0 100644 --- a/openapi_core/validation/schemas/_validators.py +++ b/openapi_core/validation/schemas/_validators.py @@ -76,7 +76,7 @@ def iter_missing_additional_properties_errors( if "additionalProperties" in schema: return - extras = set(find_additional_properties(instance, schema)) + extras = sorted(set(find_additional_properties(instance, schema))) if extras: error = "Additional properties are not allowed (%s %s unexpected)" diff --git a/tests/integration/validation/test_additional_properties_default_policy.py b/tests/integration/validation/test_additional_properties_default_policy.py index abb54576..32a1b551 100644 --- a/tests/integration/validation/test_additional_properties_default_policy.py +++ b/tests/integration/validation/test_additional_properties_default_policy.py @@ -134,6 +134,43 @@ def test_response_validation_strict_rejects_extra_properties(): openapi.validate_response(request, response) +def test_request_validation_strict_error_message_is_stable(): + """Test that error messages are deterministic when multiple extra properties exist.""" + config = Config(additional_properties_default_policy="forbid") + openapi = OpenAPI.from_dict(_spec_dict(), config=config) + + request = MockRequest( + "http://example.com", + "post", + "/tags", + content_type="application/json", + data=json.dumps( + { + "tag_name": "my-tag", + "zebra": "z data", + "apple": "a data", + "mango": "m data", + } + ).encode("utf-8"), + ) + + # Collect error messages from multiple validation attempts + messages = [] + for _ in range(10): + with pytest.raises(InvalidRequestBody) as exc_info: + openapi.validate_request(request) + messages.append(str(exc_info.value)) + + assert ( + len(set(messages)) == 1 + ), f"Error messages are not stable: {messages}" + + error_message = messages[0] + assert ( + "'apple', 'mango', 'zebra'" in error_message + ), f"Properties not in alphabetical order: {error_message}" + + def test_response_validation_strict_allows_explicit_additional_properties_true(): spec_dict = _spec_dict() spec_dict["components"]["schemas"]["Tag"]["additionalProperties"] = True