Skip to content

Bug: retry decorator swallows original exception context #29

@bnusunny

Description

@bnusunny

Description

The retry decorator in samcli/lib/utils/retry.py swallows the original exception when all retries are exhausted, making it impossible to diagnose the root cause of failures.

Code location

samcli/lib/utils/retry.py, the wrapper function:

while remaining_attempts >= 1:
    try:
        return func(*args, **kwargs)
    except exc:
        time.sleep(math.pow(2, retry_attempt) * delay)
        retry_attempt = retry_attempt + 1
        remaining_attempts = remaining_attempts - 1
raise exc_raise(exc_raise_msg)

Problem

When all retry attempts are exhausted, the decorator raises exc_raise(exc_raise_msg) without chaining the original exception using raise ... from last_exception. This means:

  1. The original traceback is lost
  2. Debugging becomes difficult since the actual error details are hidden behind a generic message
  3. Python's exception chaining (__cause__) is not used

Expected behavior

The last caught exception should be chained using raise exc_raise(exc_raise_msg) from last_exception so the original error context is preserved in the traceback.

Fix

Capture the last exception and chain it:

last_exception = None
while remaining_attempts >= 1:
    try:
        return func(*args, **kwargs)
    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) from last_exception

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions