Repository navigation
[Bug]: Codex pool registration couples account persistence to warmup success #3846
Description
Client or integration
OpenCodex dashboard
Area
Authentication and account pool
Summary
I experienced a registration failure when adding a Codex pool account whose weekly allowance was exhausted. Source inspection confirms a blocking path: after OAuth completes, account registration requires a successful inference warmup, and any warmup failure stops pool-account persistence.
Expected behavior: an authenticated, identity-verified account can be registered as quota-limited, without being marked inference-ready or selected for requests until recovery. Registration should preserve the account for later use without changing the provider's usage limits.
This is a request to revise an existing validation policy, not a claim that the warmup gate was accidental. The confirmed scope is the Codex pool registration path; other providers have not been shown to share this defect.
Reproduction
Scenario to confirm with a live account:
- Use a ChatGPT account whose Codex weekly allowance is already exhausted.
- Add that account through the dashboard Codex account-pool OAuth flow.
- Complete OAuth successfully.
- If the subsequent warmup returns a quota rejection, the login flow becomes
errorbefore the new pool account is persisted.
Evidence boundary: the registration failure was experienced by the reporter on a real exhausted account. The installed source and current dev gate were inspected, but no live exhausted-account response was captured and no behavioral reproduction test was executed for this report. The exact upstream rejection shape in this incident remains unconfirmed.
The source explains how this can occur:
warmup.tssends a real/backend-api/codex/responsesrequest and requiresresponse.completed. Non-2xx responses and streamedresponse.failed,response.incomplete, orerrorevents fail verification. Only HTTP 400 has the fallback-model retry.auth-api.tscallsverifyCodexAccountWarmupbefore persisting the pool account. A failed result sets the OAuth login state toerrorand exits. Its generic message asks the user to reauthenticate even when the cause can be quota or availability.
Version
Installed package inspected: @bitkyc08/opencodex 2.45.0.
The blocking gate is also present on inspected dev commit 5fdf9bbdd9ff7657f0b6d7101697317d708af0e7.
Operating system
Windows 11 Pro, version 10.0.26200. The inspected warmup/registration gate has no OS-specific branch; macOS/Linux execution was not tested.
Provider and model
OpenAI / ChatGPT Codex account pool. The inspected warmup defaults to gpt-5.4-mini, with gpt-5.5 as a fallback for HTTP 400. This concerns account registration rather than a user-selected conversation model.
Logs or error output
No live account log is attached. The source-generated message is:
Codex account warmup failed. Reauthenticate the account and try again.
For an HTTP 429 warmup rejection, the code appends (http_status:429). Streamed quota rejections can instead become a stream failure reason; HTTP 429 must not be assumed to be the only quota signal.
Historical decision and related work
The July 5 warmup design and implementation record explains the original objective: metadata lookup success did not prove that a Codex Responses request would work. It explicitly includes HTTP 429/5xx among warmup failures, considers saving with an unknown warmup status for transient failures, and records an implementation that does not add the account when warmup fails.
The proposed change preserves that distinction: stored/authenticated must not imply inference-ready.
- July 9 fix: addressed second-account registration failures on HTTP 400 through fallback-model retry.
- fix(codex): bound warmup response bodies #1725: improved warmup body bounds and deadlines while preserving the validation gate.
- fix(codex): remove raw-token account import #1560: removed the manual raw-token import escape hatch; restoring it is not proposed here.
- [Bug]: Weekly-exhausted Codex account never rotates — incomplete quota terminal recorded as success (2.43.0) #3795: reports a serving-time weekly quota rejection as an incomplete stream. It concerns already-registered accounts, but demonstrates why registration classification should not handle only HTTP 429.
Suggested fix
Separate credential/identity verification, account persistence, and inference readiness in the Codex add/reauth flow:
- Preserve OAuth, identity matching, duplicate checks, and existing credential generation/locking protections.
- When authentication and identity are established independently and the probe is classified as quota-limited, persist the account with that restriction. Do not record a successful inference-validation timestamp or mark it healthy.
- Keep the account ineligible for routing until quota recovery is confirmed. Preserve the restriction through restart and handle unknown reset times explicitly.
- Show an actionable quota-limited result instead of asking for reauthentication. Keep invalid credentials and identity mismatches on their existing rejection paths.
- Classify provider responses using HTTP status plus bounded structured error/terminal evidence. Do not treat every 429/403 as proof of valid authentication, and preserve the secret-safe error handling from fix(codex): bound warmup response bodies #1725.
Transport failures and unsupported-model responses should remain distinct from quota and authentication failures; changing their persistence policy can be a separate follow-up. A scoped Codex fix can reuse existing account-health concepts without claiming all providers need the same change.
Suggested regression coverage:
- Successful OAuth + completed warmup retains normal registration behavior.
- Independently authenticated account + HTTP quota rejection is stored as quota-limited and cannot route.
- A structured streamed quota rejection follows the same path; an unrelated incomplete stream does not.
- Invalid authentication and mismatched identity are still rejected.
- Same-identity reauthentication while quota-limited follows the intended credential-replacement contract without marking inference validation successful.
- Restart and quota-refresh failures do not silently turn the restricted account healthy; confirmed recovery restores eligibility.
Maintainer alignment requested: is the registration/readiness distinction acceptable as a revision of the July policy? Any implementation PR would target dev and follow the authentication-area sponsorship requirement.
Checks
- I searched existing issues and documentation.
- I removed secrets, tokens, account details, request credentials, and personal data.
Activity
lidge-jun commentedon Sep 7, 2026
리뷰 · 우선순위 62 / 80
이슈 #3846은 Codex 계정 풀에 계정을 새로 넣는 순간에 생기는 정책 구멍입니다. 제보 요지는 단순합니다. OAuth는 이미 끝났고 신원도 확인됐는데, 주간(weekly) 한도가 바닥난 계정은
warmup(진짜 Responses 한 번 보내서response.completed를 확인하는 검사)이 실패하면 풀에 저장조차 안 됩니다. 대시보드 로그인은error로 끝나고, 사용자는 “다시 로그인하라”는 말만 봅니다. 기대 동작은 다릅니다. 인증·신원은 통과했으면 계정을 쿼터 제한 상태로 저장하고, 한도가 회복될 때까지는 라우팅 후보에서만 빼 두자는 것입니다. “저장된 계정”과 “지금 바로 추론에 쓸 수 있는 계정”을 갈라야 한다는 요청입니다.지금
devHEAD(0d8b0cd1e, package 2.46.0, axis1 클로즈아웃 #3847까지 반영)에서도 그 게이트는 그대로입니다.src/codex/auth-api.ts의verifyCodexAccountWarmup(약 558–577줄)은warmCodexAccount가 성공해야만validatedAt을 돌려줍니다. 실패하면 HTTP 401 JSON으로Codex account warmup failed. Reauthenticate the account and try again.와code: codex_warmup_failed를 내고, 이유 문자열만reason에 붙입니다. OAuth 콜백 본문(약 2577–2586줄)은 warmup이ok가 아니면setCodexLoginState(..., status: "error")후 바로 break합니다. 그 아래의saveCodexAccountCredential/markCodexAccountValidated/ 풀 row 커밋은 실행되지 않습니다. 즉 제보가 읽은 “warmup 실패 = 영속화 없음”은 HEAD에서도 사실입니다.src/codex/warmup.ts도 제보와 같습니다. 기본 모델gpt-5.4-mini로chatgpt.com/backend-api/codex/responses에 스트림 요청을 보내고, HTTP가 2xx가 아니면http_status(예: 429면http_status:429)로 떨어집니다. 스트림 안에서는response.failed/response.incomplete/error/ 종단 없음이 전부 실패입니다. HTTP 400만 fallback 모델(gpt-5.5) 재시도가 있습니다. #3795에서 이미 확인했듯 ChatGPT 주간 한도는 종종 HTTP 429가 아니라 mid-stream incomplete/usage-limit 형태로 옵니다. 그래서 등록 경로도 “429만 쿼터”로 보면 안 됩니다. 제보가 산 소스와 라이브 재현을 구분해 둔 점(설치된 2.45.0 +dev5fdf9bbdd소스 검사, 라이브 exhausted 계정 응답은 미캡처)도 그대로 유지합니다.이 게이트는 사고가 아니라 의도된 설계입니다.
devlog/_fin/260705_codex-auth-warmup-refresh/00_plan.md는 “메타데이터만 되고 Responses가 안 되는 계정”을 막으려고 warmup을 넣었고, 실패 시 계정을 안 넣는 구현을 남겼습니다. 그 뒤 #1725(본문 바운드·데드라인), ceb90b5(HTTP 400 두 번째 계정), #1560(수동 raw-token import 제거)도 게이트 자체는 유지했습니다. 그래서 #3846은 “버그 고쳐라”보다 정책 개정 제안에 가깝습니다. 방금 끝난 axis1(#3825 서빙 계정 쿼터 귀속, #3827 암호화 태스크 복구 사유, #3842 Aside 파일 identity, #3847 delivery archive)은 이미 풀에 들어 있는 계정의 서빙·복구 쪽이고, 이 등록 게이트는 건드리지 않았습니다. #3795는 “이미 등록된 계정”의 weekly incomplete 서빙 쐐기(#3791이dev에 들어감)라서, #3846과 같은 뿌리(쿼터 ≠ 인증 실패)를 공유하지만 등록 시점 문제는 아직 열려 있습니다.고칠 때 조심할 점은 제보가 이미 잘 갈라 둔 경계입니다. (1) OAuth·신원 매칭·중복 검사·credential lock은 그대로 두고, (2) 독립적으로 인증된 뒤 프로브가 쿼터 제한으로 분류되면 계정은 저장하되
markCodexAccountValidated/healthy 타임스탬프는 남기지 않으며, (3) 라우팅 비적격은 재시작 후에도 유지하고, (4) 메시지는 “다시 로그인”이 아니라 쿼터 제한 안내, (5) 잘못된 인증·신원 불일치는 기존 거절 경로를 유지합니다. 분류는 HTTP 상태 + 바운드된 structured terminal(#1725 비밀 안전)이어야 하고, 모든 429/403을 “인증 OK”로 취급하면 안 됩니다. transport / unsupported-model 영속화는 후속으로 남겨도 됩니다. types.ts/config.ts 분할과 무관한 account-pool 정책이라 close-don't-rebase 대상이 아닙니다.src/codex/auth-api.ts:558-577 - verifyCodexAccountWarmup 실패 시 항상 Reauthenticate 문구 + 401; 쿼터와 인증 실패를 사용자에게 갈라 주지 않음
src/codex/auth-api.ts:2577-2586 - warmup 실패 시 login state error로 종료; 그 아래 credential/풀 영속화에 도달하지 않음
src/codex/warmup.ts:240-290,165+ - 실 Responses + response.completed 필수; non-2xx와 stream failed/incomplete/error 전부 실패; 400만 fallback
src/codex/account-store.ts markCodexAccountValidated / account-runtime-state needsReauth - “검증됨/재인증 필요” 개념은 있으나, “쿼터 제한으로 저장됐지만 추론 비적격” 등록 전용 상태가 없음
관련 #3795/#3791 - 서빙 중 incomplete 쿼터 귀속은 HEAD에 있음; 등록 게이트와는 별개 follow-up
메인테이너의 판단이 필요한 지점
dev에 올릴지, axis1 잔여(mise upgrade leaves launchd proxy running an old OpenCodex version #3464/unreadable_encrypted_agent_task intermittently fails routed V2 subagent dispatch (strict recovery envelope; no retry during chatgpt.com 5xx windows) #3661)와 묶지 말고 단독 트랙으로 둘지너의 추천
라벨(
bug,account-pool)은 유지하고 이슈는 열어 둔다. 구현 PR은 Codex 등록 경로만 좁게: OAuth·신원 통과 후 warmup이 쿼터로 분류되면 계정을 영속화하고, validated/healthy로 표시하지 않으며, 라우팅에서는 제외하고, UI/로그인은 재인증이 아니라 쿼터 제한을 보여 준다. 회귀 테스트는 제보 제안 6개(성공 warmup 유지, HTTP 쿼터 저장, streamed 쿼터 저장, 잘못된 인증 거절, 동일 신원 reauth, 재시작 후 비적격 유지)를 최소셋으로 가져간다. #3795와 한 PR로 묶지 말고, “등록 시 readiness 분리”만 닫는다. 새 설정 플래그는 넣지 않는다.이 댓글은 grok-bot이 작성했습니다
Merge pull request #3848 from shaun0927/fix/codex-quota-registration-…
lidge-jun commentedon Sep 9, 2026
Fixed on by #3848 (merge f8f93af). An authenticated usage read that confirms exhausted quota now registers the account as validation-pending instead of failing registration on the warmup gate; the account stays out of routing and manual selection across restart and token refresh, and a human dashboard Refresh quotas action finishes validation. Thanks @DaedalGames and @shaun0927. Closing manually because PRs here target .
Merge pull request lidge-jun#3848 from shaun0927/fix/codex-quota-regi…