You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@beam.apache.org by cv...@apache.org on 2026/10/19 03:14:27 UTC

(beam) branch master updated: Preserve HTTP errors when quota response is not JSON (#40631)

This is an automated email from the ASF dual-hosted git repository.

claudevdm pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/beam.git


The following commit(s) were added to refs/heads/master by this push:
     new 707b951e5e0 Preserve HTTP errors when quota response is not JSON (#40631)
707b951e5e0 is described below

commit 707b951e5e04015d195a62b5ab51d2088391fc7f
Author: GAURAV THAKUR <gr...@gmail.com>
AuthorDate: Mon Oct 19 08:44:19 2026 +0530

    Preserve HTTP errors when quota response is not JSON (#40631)
---
 sdks/python/apache_beam/utils/retry.py      |  2 +-
 sdks/python/apache_beam/utils/retry_test.py | 18 ++++++++++++++++++
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/sdks/python/apache_beam/utils/retry.py b/sdks/python/apache_beam/utils/retry.py
index 03e42829b84..063446472fe 100644
--- a/sdks/python/apache_beam/utils/retry.py
+++ b/sdks/python/apache_beam/utils/retry.py
@@ -183,7 +183,7 @@ def retry_on_server_errors_timeout_or_quota_issues_filter(exception):
         if not isinstance(content, dict):
           content = json.loads(exception.content)
         return content["error"]["errors"][0]["reason"] in _RETRYABLE_REASONS
-      except (KeyError, IndexError, TypeError) as e:
+      except (KeyError, IndexError, TypeError, ValueError) as e:
         _LOGGER.warning(
             "Could not determine if HttpError is transient. "
             "Will not retry: %s",
diff --git a/sdks/python/apache_beam/utils/retry_test.py b/sdks/python/apache_beam/utils/retry_test.py
index 05cc6e6a7f4..8d9e006e00c 100644
--- a/sdks/python/apache_beam/utils/retry_test.py
+++ b/sdks/python/apache_beam/utils/retry_test.py
@@ -141,6 +141,24 @@ class RetryTest(unittest.TestCase):
         500)
     self.assertEqual(len(self.clock.calls), 10)
 
+  @unittest.skipIf(HttpError is None, 'google-apitools is not installed')
+  def test_quota_filter_preserves_http_error_with_non_json_content(self):
+    error = HttpError({'status': '403'},
+                      '<html>upstream error</html>',
+                      'https://example.test')
+
+    @retry.with_exponential_backoff(
+        clock=self.clock,
+        retry_filter=retry.retry_on_server_errors_timeout_or_quota_issues_filter
+    )
+    def fail():
+      raise error
+
+    with self.assertRaises(HttpError) as raised:
+      fail()
+    self.assertIs(raised.exception, error)
+    self.assertEqual(self.clock.calls, [])
+
   def test_with_explicit_initial_delay(self):
     self.assertRaises(
         NotImplementedError,