From 5e2f14e6b4d40c1d94bd08e2af9c66406681e4dc Mon Sep 17 00:00:00 2001 From: Strift Date: Tue, 23 Jun 2026 14:14:40 +0800 Subject: [PATCH 1/2] Do not swallow non-JSON http error responses --- meilisearch/errors.py | 13 ++++++++----- tests/errors/test_api_error_meilisearch.py | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/meilisearch/errors.py b/meilisearch/errors.py index 57ca2bc2..0c9f35e8 100644 --- a/meilisearch/errors.py +++ b/meilisearch/errors.py @@ -35,11 +35,14 @@ def __init__(self, error: str, request: Response) -> None: self.type = None if request.text: - json_data = json.loads(request.text) - self.message = json_data.get("message") - self.code = json_data.get("code") - self.link = json_data.get("link") - self.type = json_data.get("type") + try: + json_data = json.loads(request.text) + self.message = json_data.get("message") or request.text + self.code = json_data.get("code") + self.link = json_data.get("link") + self.type = json_data.get("type") + except json.JSONDecodeError: + self.message = request.text else: self.message = error super().__init__(self.message) diff --git a/tests/errors/test_api_error_meilisearch.py b/tests/errors/test_api_error_meilisearch.py index 0c91aeeb..61de3c59 100644 --- a/tests/errors/test_api_error_meilisearch.py +++ b/tests/errors/test_api_error_meilisearch.py @@ -35,6 +35,26 @@ def test_meilisearch_api_error_no_code(mock_post): client.create_index("some_index") +@patch("requests.post") +def test_meilisearch_api_error_falls_back_to_raw_message_for_non_json_response(mock_post): + """Uses raw response text when an API error body is not valid JSON.""" + mock_post.configure_mock(__name__="post") + mock_response = requests.models.Response() + mock_response.status_code = 502 + mock_response._content = b"Bad Gateway" # pylint: disable=protected-access + mock_post.return_value = mock_response + + with pytest.raises(MeilisearchApiError) as exc: + client = meilisearch.Client(BASE_URL, MASTER_KEY + "123") + client.create_index("some_index") + + assert exc.value.status_code == 502 + assert exc.value.message == "Bad Gateway" + assert exc.value.code is None + assert exc.value.link is None + assert exc.value.type is None + + def test_version_error_hint_message(): mock_response = requests.models.Response() mock_response.status_code = 408 From ef693f6e7ca224a6efbf83acb6063a1df31b0286 Mon Sep 17 00:00:00 2001 From: Strift Date: Tue, 23 Jun 2026 14:30:02 +0800 Subject: [PATCH 2/2] Handle non-dict valid JSON --- meilisearch/errors.py | 11 +++++++---- tests/errors/test_api_error_meilisearch.py | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/meilisearch/errors.py b/meilisearch/errors.py index 0c9f35e8..87583b1c 100644 --- a/meilisearch/errors.py +++ b/meilisearch/errors.py @@ -37,10 +37,13 @@ def __init__(self, error: str, request: Response) -> None: if request.text: try: json_data = json.loads(request.text) - self.message = json_data.get("message") or request.text - self.code = json_data.get("code") - self.link = json_data.get("link") - self.type = json_data.get("type") + if isinstance(json_data, dict): + self.message = json_data.get("message") or request.text + self.code = json_data.get("code") + self.link = json_data.get("link") + self.type = json_data.get("type") + else: + self.message = request.text except json.JSONDecodeError: self.message = request.text else: diff --git a/tests/errors/test_api_error_meilisearch.py b/tests/errors/test_api_error_meilisearch.py index 61de3c59..e80e962c 100644 --- a/tests/errors/test_api_error_meilisearch.py +++ b/tests/errors/test_api_error_meilisearch.py @@ -55,6 +55,26 @@ def test_meilisearch_api_error_falls_back_to_raw_message_for_non_json_response(m assert exc.value.type is None +@patch("requests.post") +def test_meilisearch_api_error_falls_back_to_raw_message_for_non_object_json_response(mock_post): + """Uses raw response text when parsed JSON is not an object.""" + mock_post.configure_mock(__name__="post") + mock_response = requests.models.Response() + mock_response.status_code = 502 + mock_response._content = b'["Bad Gateway"]' # pylint: disable=protected-access + mock_post.return_value = mock_response + + with pytest.raises(MeilisearchApiError) as exc: + client = meilisearch.Client(BASE_URL, MASTER_KEY + "123") + client.create_index("some_index") + + assert exc.value.status_code == 502 + assert exc.value.message == '["Bad Gateway"]' + assert exc.value.code is None + assert exc.value.link is None + assert exc.value.type is None + + def test_version_error_hint_message(): mock_response = requests.models.Response() mock_response.status_code = 408