Let an error body that is an array still be read

Google answers some failures with a JSON array holding the object every
other provider sends on its own. _extract_error called .get() on it and
raised AttributeError, which is not the ApiError every caller is holding,
so a 503 from Google took the whole dictation down instead of pasting the
raw transcript with the failure shown beside it.

Found by dictating against a Google AI Studio outage:

  HTTP Error 503: Service Unavailable
  AttributeError: 'list' object has no attribute 'get'

It runs while an exception is being raised, so it now ends in a string
whatever arrives.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
oztturk
2026-08-26 16:29:41 +03:00
co-authored by Claude Opus 5
parent 1812461612
commit 1ffc3cff9d
2 changed files with 26 additions and 0 deletions
+13
View File
@@ -119,9 +119,22 @@ class ExtractError(unittest.TestCase):
body = json.dumps({"error": {"code": 42}})
self.assertIn("42", api._extract_error(body))
def test_an_error_wrapped_in_an_array(self):
"""Google's 503 arrives this way, and .get() on a list raises."""
body = json.dumps([{"error": {"code": 503,
"message": "The model is overloaded."}}])
self.assertEqual(api._extract_error(body), "The model is overloaded.")
def test_a_body_that_is_not_json(self):
self.assertEqual(api._extract_error("<html>502</html>"), "<html>502</html>")
def test_no_shape_at_all_still_comes_back_as_a_string(self):
"""It runs while an ApiError is being raised: throwing here would
escape the `except ApiError` holding the raw transcript."""
for body in ("[]", "[1, 2]", '"a string"', "null", "17"):
with self.subTest(body=body):
self.assertIsInstance(api._extract_error(body), str)
def test_a_wall_of_html_is_cut_short(self):
self.assertEqual(len(api._extract_error("x" * 5000)), 300)