Skip to content

[correctness/medium] GitHub _request() crashes on non-numeric rate-limit headers and ignores secondary 429s #68

Description

@tomharris

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    auditSurfaced by /engineer-agent audit-codeaudit:correctnessAudit finding: correctness

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions