diff --git a/google/api_core/retry/retry_base.py b/google/api_core/retry/retry_base.py index 263b4ccf3..75a3d1384 100644 --- a/google/api_core/retry/retry_base.py +++ b/google/api_core/retry/retry_base.py @@ -164,8 +164,10 @@ def build_retry_error( src_exc, ) elif exc_list: - # return most recent exception encountered - return exc_list[-1], None + # return most recent exception encountered and its cause + final_exc = exc_list[-1] + cause = getattr(final_exc, '__cause__', None) + return final_exc, cause else: # no exceptions were given in exc_list. Raise generic RetryError return exceptions.RetryError("Unknown error", None), None diff --git a/tests/unit/retry/test_retry_base.py b/tests/unit/retry/test_retry_base.py index 212c4293b..78fdb9171 100644 --- a/tests/unit/retry/test_retry_base.py +++ b/tests/unit/retry/test_retry_base.py @@ -74,6 +74,26 @@ def test_build_retry_error_empty_list(): assert src.message == "Unknown error" +def test_build_retry_error_preserves_cause(): + """ + build_retry_error should preserve __cause__ from chained exceptions. + """ + from google.api_core.retry import build_retry_error + from google.api_core.retry import RetryFailureReason + + # Create an exception with explicit cause + cause = ValueError("root cause") + exc = RuntimeError("wrapper") + exc.__cause__ = cause + + src, found_cause = build_retry_error( + [exc], RetryFailureReason.NON_RETRYABLE_ERROR, None + ) + + assert src is exc + assert found_cause is cause + + def test_build_retry_error_timeout_message(): """ should provide helpful error message when timeout is reached