From d81871b8644e3b5dcc36b63904f7e3463c92a947 Mon Sep 17 00:00:00 2001 From: Vineeth Sai Date: Sat, 13 Jun 2026 03:15:22 -0700 Subject: [PATCH] Fix TypeError when building the key error message for a tuple key When a key's value failed validation, the error message was built with `"Key '%s' error:" % nkey`. If the key is a tuple (including the empty tuple), `%` treats it as the format arguments rather than a single value, so an empty tuple key raised `TypeError: not enough arguments for format string` and other tuple keys would consume their elements as multiple format args. Wrap the key in a single-element tuple (`% (nkey,)`) so it is always formatted as one value. Fixes #253 Co-Authored-By: Claude Opus 4.8 (1M context) --- schema/__init__.py | 2 +- test_schema.py | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/schema/__init__.py b/schema/__init__.py index 3a918d0..287d958 100644 --- a/schema/__init__.py +++ b/schema/__init__.py @@ -494,7 +494,7 @@ def validate(self, data: Any, **kwargs: Dict[str, Any]) -> Any: svalue, error=e, ignore_extra_keys=i ).validate(value, **kwargs) except SchemaError as x: - k = "Key '%s' error:" % nkey + k = "Key '%s' error:" % (nkey,) message = self._prepend_schema_name(k) raise SchemaError( [message] + x.autos, diff --git a/test_schema.py b/test_schema.py index 8936e53..e45d51f 100644 --- a/test_schema.py +++ b/test_schema.py @@ -2059,3 +2059,13 @@ def test_callable_error(): except SchemaError as ex: e = ex assert e.errors == ["This is the error message"] + + +def test_tuple_key_error_message_does_not_crash(): + # Regression test for #253: a tuple dict key (including the empty tuple) must not raise + # "TypeError: not enough arguments for format string" when building the key error message. + assert Schema({(): [(str,)]}).is_valid({(): ["foo", ("bar",)]}) is False + + with raises(SchemaError) as exc_info: + Schema({("a", "b"): int}).validate({("a", "b"): "not-an-int"}) + assert "Key '('a', 'b')' error:" in exc_info.value.code