oauth/xai: Retry-After is capped at 2000ms in postXaiToken, so a 429 with Retry-After: 60 retries after 2s #4045
Description
Where
src/oauth/xai.ts line 98 (retryDelay), on dev (blob f876b18):
return Math.min(2000,Math.max(j,seconds*1000));Problem
Math.min(2000, ...) wraps the server-provided Retry-After value, so any delay the token endpoint asks for is truncated to 2 seconds. Measured on Node 24 with the function extracted verbatim:
retryDelay(2, "60", () => 0.5) -> 2000
When auth.x.ai answers 429 with Retry-After: 60, postXaiToken sleeps 2s, hits 429 again, and burns all 3 attempts in ~4s instead of honoring the server. RFC 9110 §10.2.3 treats Retry-After as a value to honor, not a ceiling to clamp.
Fix
Apply the 2000ms cap to the jitter only, and honor Retry-After (with a generous absolute ceiling such as 60s to avoid pathological values):
if (seconds > 0) return Math.min(seconds * 1000, 60_000);
return Math.min(2000, j);Repro
const random = () => 0.5;
retryDelay(1, "60", random); // expected 60000, got 2000Found while porting this module into ima2-gen (devlog 260909_grok_native_oauth/001_opencodex_port_spec.md D1). Related: the HTTP-date form of Retry-After is also ignored (separate issue).
Activity
lidge-jun commentedon Sep 8, 2026
리뷰 · 우선순위 62 / 80
이 이슈는 Grok(xAI) OAuth 토큰 POST가 서버가 시킨 대기 시간을 지키지 못하는 버그입니다. 지금
devHEAD cfff026d5의src/oauth/xai.tsretryDelay(대략 98행)는 이렇게 끝납니다.서버가
Retry-After: 60을 줘도Math.min(2000, …)때문에 항상 최대 2초만 쉽니다. 이슈가 Node 24에서 함수만 빼서 측정한 값도retryDelay(2, "60", () => 0.5) -> 2000입니다.postXaiToken은 429/5xx에서 최대 3번 재시도하므로, 실제로는 약 4초 안에 세 번을 다 태우고 실패합니다. RFC 9110 §10.2.3는Retry-After를 존중하라고 말하고, 지금 코드는 존중이 아니라 상한으로 잘라 버립니다.왜 지금 큐에 올릴 만하냐면,
dev는 패키지 2.49.0이고 Grok/xAI OAuth(XaiOAuthFlow/refreshXai)가 account-pool·로그인 경로에 이미 들어가 있습니다. 토큰 엔드포인트가 짧게라도 rate-limit을 걸면 로그인·리프레시가 “네트워크/토큰 요청 실패”로 보이기 쉽습니다. 같은 파일의 HTTP-date 파싱 구멍(#4046)과 abort 재시도 구멍(#4047)과 한 묶음으로 고치는 편이 싸습니다. types.ts/config.ts 분할과는 무관합니다.제안 수정은 명확합니다. 서버가 준 초 단위 값은 그대로(다만 60초 같은 절대 천장) 쓰고, 2000ms 캡은 지터 폴백에만 적용합니다.
라인 98 · retryDelay -
Math.min(2000, Math.max(j, seconds*1000))가 Retry-After를 2초로 자릅니다. 측정값과 코드가 일치합니다.경로 postXaiToken 재시도 루프 - 429마다 짧은 sleep만 하니 서버 의도(60초)와 클라이언트 행동(2초×N)이 어긋납니다. 사용자에게는 간헐적 Grok 로그인 실패로 보입니다.
경로 테스트 - 이슈 본문의
retryDelay(1,"60")단위 테스트만 있어도 회귀를 막을 수 있습니다. 지금은 공개 테스트가 안 보입니다.메인테이너의 판단이 필요한 지점
너의 추천
수락하세요.
help wanted로 두되 우선은 중간 이상입니다. 가능하면 #4046과 같은retryDelayPR에 넣고, 단위 테스트 한 줄을 같이 받으세요. close-don't-rebase 대상이 아닙니다.이 댓글은 grok-bot이 작성했습니다
lidge-jun commentedon Sep 9, 2026
Fixed on
devvia #4087 at 4a08c75.devlog: plan the xAI OAuth retry hardening unit (lidge-jun#4045, lidg…
oauth/xai: honor Retry-After and stop retrying aborted token requests (…
docs(grok): docs-first roadmap for native xAI OAuth, replacing the pr…
devlog: plan the xAI OAuth retry hardening unit (lidge-jun#4045, lidg…
oauth/xai: honor Retry-After and stop retrying aborted token requests (…