From 7e5b2e8aa98a0e846181c67126848a40dd078260 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 12 May 2026 02:10:05 +0000 Subject: [PATCH 1/3] fix: improve exhausted HTTP retry errors --- .../error_handlers/http_response_filter.py | 4 ++-- airbyte_cdk/sources/streams/http/http_client.py | 2 +- .../error_handlers/test_default_error_handler.py | 14 ++++++++++++++ .../sources/streams/http/test_http_client.py | 2 ++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/airbyte_cdk/sources/declarative/requesters/error_handlers/http_response_filter.py b/airbyte_cdk/sources/declarative/requesters/error_handlers/http_response_filter.py index 866d6b7d2..7d36e1d77 100644 --- a/airbyte_cdk/sources/declarative/requesters/error_handlers/http_response_filter.py +++ b/airbyte_cdk/sources/declarative/requesters/error_handlers/http_response_filter.py @@ -27,7 +27,7 @@ class HttpResponseFilter: Filter to select a response based on its HTTP status code, error message or a predicate. If a response matches the filter, the response action, failure_type, and error message are returned as an ErrorResolution object. For http_codes declared in the filter, the failure_type will default to `system_error`. - To override default failure_type use configured failure_type with ResponseAction.FAIL. + To override default failure_type use configured failure_type. Attributes: action (Union[ResponseAction, str]): action to execute if a request matches @@ -95,7 +95,7 @@ def matches( error_message = self._create_error_message(response_or_exception) error_message = error_message or default_error_message - if self.failure_type and filter_action == ResponseAction.FAIL: + if self.failure_type: failure_type = self.failure_type elif default_mapped_error_resolution: failure_type = default_mapped_error_resolution.failure_type diff --git a/airbyte_cdk/sources/streams/http/http_client.py b/airbyte_cdk/sources/streams/http/http_client.py index c1d0eabd6..2ba730f0b 100644 --- a/airbyte_cdk/sources/streams/http/http_client.py +++ b/airbyte_cdk/sources/streams/http/http_client.py @@ -316,7 +316,7 @@ def _send_with_retry( raise AirbyteTracedException( internal_message=f"Exhausted available request attempts. Exception: {e}", - message=f"Exhausted available request attempts. Please see logs for more details. Exception: {e}", + message=str(e), failure_type=e.failure_type or FailureType.system_error, exception=e, stream_descriptor=StreamDescriptor(name=self._name), diff --git a/unit_tests/sources/declarative/requesters/error_handlers/test_default_error_handler.py b/unit_tests/sources/declarative/requesters/error_handlers/test_default_error_handler.py index 526e5760f..50d45f364 100644 --- a/unit_tests/sources/declarative/requesters/error_handlers/test_default_error_handler.py +++ b/unit_tests/sources/declarative/requesters/error_handlers/test_default_error_handler.py @@ -41,6 +41,20 @@ error_message=None, ), ), + ( + "_with_http_response_status_400_retry_with_custom_failure_type", + 400, + HttpResponseFilter( + http_codes=[400], + action=ResponseAction.RETRY, + failure_type=FailureType.transient_error, + config={}, + parameters={}, + ), + ResponseAction.RETRY, + FailureType.transient_error, + "HTTP Status Code: 400. Error: Bad request. Please check your request parameters.", + ), ( "_with_http_response_status_400", 400, diff --git a/unit_tests/sources/streams/http/test_http_client.py b/unit_tests/sources/streams/http/test_http_client.py index 48d396cb6..543d0f927 100644 --- a/unit_tests/sources/streams/http/test_http_client.py +++ b/unit_tests/sources/streams/http/test_http_client.py @@ -838,6 +838,8 @@ def backoff_time(self, response_or_exception, attempt_count): with pytest.raises(AirbyteTracedException) as e: http_client.send_request(http_method="get", url="https://airbyte.io/", request_kwargs={}) assert e.value.failure_type == expected_failure_type + if exception_class != RateLimitBackoffException: + assert e.value.message == error_message class MockOAuthAuthenticator: From ce02fd864f7cd8b630d88cecdc272ebc1f7853a2 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 12 May 2026 02:13:16 +0000 Subject: [PATCH 2/3] test: fix response filter parametrization Co-Authored-By: bot_apk --- .../test_default_error_handler.py | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/unit_tests/sources/declarative/requesters/error_handlers/test_default_error_handler.py b/unit_tests/sources/declarative/requesters/error_handlers/test_default_error_handler.py index 50d45f364..2c1ca7f14 100644 --- a/unit_tests/sources/declarative/requesters/error_handlers/test_default_error_handler.py +++ b/unit_tests/sources/declarative/requesters/error_handlers/test_default_error_handler.py @@ -41,20 +41,6 @@ error_message=None, ), ), - ( - "_with_http_response_status_400_retry_with_custom_failure_type", - 400, - HttpResponseFilter( - http_codes=[400], - action=ResponseAction.RETRY, - failure_type=FailureType.transient_error, - config={}, - parameters={}, - ), - ResponseAction.RETRY, - FailureType.transient_error, - "HTTP Status Code: 400. Error: Bad request. Please check your request parameters.", - ), ( "_with_http_response_status_400", 400, @@ -108,6 +94,20 @@ def test_default_error_handler_with_default_response_filter( FailureType.system_error, "HTTP Status Code: 400. Error: Bad request. Please check your request parameters.", ), + ( + "_with_http_response_status_400_retry_with_custom_failure_type", + 400, + HttpResponseFilter( + http_codes=[400], + action=ResponseAction.RETRY, + failure_type=FailureType.transient_error, + config={}, + parameters={}, + ), + ResponseAction.RETRY, + FailureType.transient_error, + "HTTP Status Code: 400. Error: Bad request. Please check your request parameters.", + ), ( "_with_http_response_status_402_fail_with_default_failure_type", 402, From 3c2111684ccbe7e280bc50aa5168773d33e1e89a Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 12 May 2026 02:22:12 +0000 Subject: [PATCH 3/3] test: update response filter failure type expectation Co-Authored-By: bot_apk --- .../requesters/error_handlers/test_http_response_filter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unit_tests/sources/declarative/requesters/error_handlers/test_http_response_filter.py b/unit_tests/sources/declarative/requesters/error_handlers/test_http_response_filter.py index 87e522d4a..b1be1a043 100644 --- a/unit_tests/sources/declarative/requesters/error_handlers/test_http_response_filter.py +++ b/unit_tests/sources/declarative/requesters/error_handlers/test_http_response_filter.py @@ -178,10 +178,10 @@ {"status_code": 500}, ErrorResolution( response_action=ResponseAction.RETRY, - failure_type=FailureType.transient_error, + failure_type=FailureType.config_error, error_message="rate limits", ), - id="test_http_code_matches_failure_type_config_error_action_retry_uses_default_failure_type", + id="test_http_code_matches_failure_type_config_error_action_retry_uses_configured_failure_type", ), pytest.param( ResponseAction.RATE_LIMITED,