{"record":{"id":"9ece4f9f816a7b85","repo":"commaai/openpilot","slug":"func-name-failed-after-retry","errorCode":null,"errorMessage":"{func.__name__} failed after retry","messagePattern":"(.+?) failed after retry","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"openpilot/common/utils.py","lineNumber":274,"sourceCode":"    lines.append(gap.join(_align(row[i], widths[i]) for i in range(ncols)))\n  return \"\\n\".join(lines)\n\n\ndef retry(attempts=3, delay=1.0, ignore_failure=False):\n  def decorator(func):\n    @functools.wraps(func)\n    def wrapper(*args, **kwargs):\n      for _ in range(attempts):\n        try:\n          return func(*args, **kwargs)\n        except Exception:\n          print(f\"{func.__name__} failed, trying again\")\n          time.sleep(delay)\n\n      if ignore_failure:\n        print(f\"{func.__name__} failed after retry\")\n      else:\n        raise Exception(f\"{func.__name__} failed after retry\")\n    return wrapper\n  return decorator\n","sourceCodeStart":256,"sourceCodeEnd":277,"githubUrl":"https://github.com/commaai/openpilot/blob/516ec1e68203439a73f340f1d0b3b91eabc626ee/openpilot/common/utils.py#L256-L277","documentation":"Raised by the retry decorator in common/utils.py after the wrapped function raised on every one of `attempts` iterations. Each failure is printed and the loop sleeps `delay` seconds; when attempts are exhausted the generic Exception is raised unless ignore_failure=True, in which case None is returned (implicitly).","triggerScenarios":"A decorated function (e.g., a network fetch or params write with retry(decorator)) raising consistently: bad URL, missing dependency, permission error. Every call raises, attempts run out, and the original exception is discarded in favor of the generic one.","commonSituations":"Network endpoints down or DNS failing so all N attempts fail, a bug in the wrapped function so it always raises, or CI environments without connectivity. The bare 'print' + swallowed exception makes root-cause hunting hard.","solutions":["Fix the underlying failure: read the printed '<fn> failed, trying again' messages and the original traceback context","Increase attempts/delay only if the failure is genuinely transient (network flaps)","Set ignore_failure=True (or use the decorator's argument) if the call is best-effort","Note the original exception is lost; reproduce locally without the decorator to get the real traceback"],"exampleFix":"// before\n@retry(attempts=5, delay=1)\ndef fetch(): ...\n\n// after\ndef fetch(): ...\nfor i in range(5):\n  try:\n    return fetch()\n  except Exception as e:\n    if i == 4:\n      raise","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    result = decorated_fn()\nexcept Exception as e:\n    if str(e).endswith('failed after retry'):\n        # original exception was swallowed; reproduce it without the decorator\n        raise RuntimeError('underlying call keeps failing; run fn directly for traceback') from e\n    raise","preventionTips":["Keep retryable functions small and side-effect free so retries are safe","Log the underlying exception, not just the function name, when wrapping with @retry","Size attempts/delay to the real recovery time of the dependency (e.g. network reconnect)"],"tags":["retry","utils","network","error-handling"],"backgroundTag":null,"analyzedSha":"516ec1e68203439a73f340f1d0b3b91eabc626ee","analyzedAt":"2026-08-15T00:17:37.461Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}