GitHubClient._request() casts three rate-limit headers with bare int(), so any non-numeric
value raises ValueError that propagates through paginate() and aborts the whole sync. It also
only retries when x-ratelimit-remaining == 0, so GitHub's secondary rate limits (429 with
Retry-After set, x-ratelimit-remaining non-zero or absent) fall through to raise_for_status()
with no sleep and no retry — immediately aborting a long PR or issue sync.
Location: devrag/utils/github.py:48-58
Suggested fix:
Add a tolerant header parser and trigger the retry on Retry-After as well as exhaustion:
def _safe_int(headers, name: str, default: str) -> int:
try:
return int(headers.get(name, default))
except ValueError:
return int(default)
if resp.status_code in (403, 429):
retry_after = _safe_int(resp.headers, "retry-after", "0")
remaining = _safe_int(resp.headers, "x-ratelimit-remaining", "1")
if retry_after or remaining == 0:
reset_at = _safe_int(resp.headers, "x-ratelimit-reset", "0")
wait = retry_after if retry_after else max(reset_at - time.time(), 0) + 1
time.sleep(min(wait, 60))
resp = self._client.request(method, url, **kwargs)
Consider a bounded retry loop (up to 3 attempts) so a second consecutive 429 is also handled,
matching the SlackClient._call() pattern.
Source: Surfaced by /engineer-agent audit-code (June run); re-verified by hand against HEAD d97b2eb on 2026-07-15, confidence high.
GitHubClient._request()casts three rate-limit headers with bareint(), so any non-numericvalue raises
ValueErrorthat propagates throughpaginate()and aborts the whole sync. It alsoonly retries when
x-ratelimit-remaining == 0, so GitHub's secondary rate limits (429 withRetry-Afterset,x-ratelimit-remainingnon-zero or absent) fall through toraise_for_status()with no sleep and no retry — immediately aborting a long PR or issue sync.
Location:
devrag/utils/github.py:48-58Suggested fix:
Add a tolerant header parser and trigger the retry on
Retry-Afteras well as exhaustion:Consider a bounded retry loop (up to 3 attempts) so a second consecutive 429 is also handled,
matching the
SlackClient._call()pattern.Source: Surfaced by
/engineer-agent audit-code(June run); re-verified by hand against HEADd97b2ebon 2026-07-15, confidence high.