From 929f52b408eb4a154c0267a753fb389fa3ab9e83 Mon Sep 17 00:00:00 2001 From: dreamcreated Date: Thu, 19 Mar 2026 10:11:48 +0800 Subject: [PATCH] fix: preserve original exception context in retry decorator When all retry attempts are exhausted, the decorator previously raised exc_raise(exc_raise_msg) without chaining the original exception, making it impossible to diagnose the root cause from the traceback. Fix: capture the last caught exception and chain it using 'raise ... from last_exception' so Python's exception chaining (__cause__) is preserved in the traceback. Fixes: bnusunny/aws-sam-cli#29 --- samcli/lib/utils/retry.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/samcli/lib/utils/retry.py b/samcli/lib/utils/retry.py index bfe8ccd4c2..ea3b1d0192 100644 --- a/samcli/lib/utils/retry.py +++ b/samcli/lib/utils/retry.py @@ -26,14 +26,16 @@ def retry_wrapper(func): def wrapper(*args, **kwargs): remaining_attempts = attempts retry_attempt = 1 + last_exception = None while remaining_attempts >= 1: try: return func(*args, **kwargs) - except exc: + except exc as e: + last_exception = e time.sleep(math.pow(2, retry_attempt) * delay) retry_attempt = retry_attempt + 1 remaining_attempts = remaining_attempts - 1 - raise exc_raise(exc_raise_msg) + raise exc_raise(exc_raise_msg) from last_exception return wrapper