From 29f2e8122726014c42604d70851814d7267edba0 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 13 Aug 2026 19:13:49 +0000 Subject: [PATCH] feat: expose validation error messages on invalid input errors Port the getValidationErrorMessages interface from the JavaScript SDK. SeamHttpInvalidInputError now carries the validation_errors from the API error response and exposes get_validation_error_messages(param_name), which returns the messages for a request parameter or an empty list when that parameter has none. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_012RfnESV5b57QDoxMggXdM9 --- seam/client.py | 1 + seam/exceptions.py | 15 ++++++++++++++- test/http_error_test.py | 14 ++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/seam/client.py b/seam/client.py index f78fefdf..518fb8b1 100644 --- a/seam/client.py +++ b/seam/client.py @@ -146,6 +146,7 @@ def _handle_error_response(self, response: Response): } if error_type == "invalid_input": + error_details["validation_errors"] = error.get("validation_errors") raise SeamHttpInvalidInputError(error_details, status_code, request_id) raise SeamHttpApiError(error_details, status_code, request_id) diff --git a/seam/exceptions.py b/seam/exceptions.py index 9a8367b7..7e7c2327 100644 --- a/seam/exceptions.py +++ b/seam/exceptions.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, Optional +from typing import Any, Dict, List, Optional from .resources import ActionAttempt @@ -86,6 +86,19 @@ def __init__( super().__init__(error, status_code, request_id) self.code = "invalid_input" + self._validation_errors = error.get("validation_errors") or {} + + def get_validation_error_messages(self, param_name: str) -> List[str]: + """ + The validation messages for a request parameter, or an empty list when + that parameter has none. + + :param param_name: Name of the request parameter + :type param_name: str + :rtype: List[str] + """ + + return self._validation_errors.get(param_name, {}).get("_errors", []) # Action Attempt diff --git a/test/http_error_test.py b/test/http_error_test.py index dd30329b..00427720 100644 --- a/test/http_error_test.py +++ b/test/http_error_test.py @@ -45,6 +45,20 @@ def test_seam_http_throws_invalid_input_error(server): assert err.status_code == 400 assert err.code == "invalid_input" assert err.request_id.startswith("request") + assert err.get_validation_error_messages("device_ids") == [ + "Expected array, received number" + ] + + +def test_seam_http_invalid_input_error_has_no_messages_for_unknown_param(server): + endpoint, seed = server + + seam = Seam(api_key=seed["seam_apikey1_token"], endpoint=endpoint) + + with pytest.raises(SeamHttpInvalidInputError) as exc_info: + seam.devices.list(device_ids=4242) + + assert exc_info.value.get_validation_error_messages("non_existent_param") == [] def test_seam_http_throws_http_error_on_non_standard_response(server):