Skip to content

[Bug][2.40.0][Codex CLI/App] Plus account entitled to GPT-5.6 works natively but opencodex forwarding returns 401 "selected ChatGPT account does not support this model" #3352

Closed

Description

@ZhenyuXiao

Client or integration

Codex CLI (installed via Scoop, v0.153.0) using ChatGPT login, routed through the opencodex proxy (default provider = openai passthrough).

Version

opencodex 2.40.0 (codex-cli 0.153.0)

Operating system

Windows 11 Pro 24H2 (build 26100, x64)

Area

Authentication / entitlement / model catalog (account-gated native models)

Summary

A valid ChatGPT Plus account (subscription active 2026-08-22 → 2026-09-22) can use gpt-5.6-sol / gpt-5.6-terra / gpt-5.6-luna:

  • Without opencodex (native Codex): codex exec -m gpt-5.6-luna "…" succeeds.
  • Through opencodex 2.40.0: the same request fails with 401 Unauthorized: The selected ChatGPT account does not support this model.

ocx models live shows only the four non-gated native OpenAI rows (gpt-5.5 / gpt-5.4 / gpt-5.4-mini / gpt-5.3-codex-spark); the GPT-5.6 trio is missing.

This looks like a false-negative of the account-gated (fail-closed) entitlement projection, in the same family as #2886 / #3022 / #3023, and it is still reproducible on 2.40.0 even though the account is genuinely entitled (native requests succeed).

Reproduction

  1. codex login with a Plus account that is entitled to GPT-5.6 (stored in ~/.codex/auth.json, plan=plus).
  2. ocx status shows the main account as healthy with credentials.
  3. ocx restore back so Codex routes through the opencodex proxy.
  4. ocx models live: native OpenAI rows are only the four non-gated models; no gpt-5.6-*.
  5. Attempt to surface and use GPT-5.6 through opencodex:
    • ocx models enable gpt-5.6-sol → prints "Enabled", but the row is removed again on the next catalog sync (not durable).
    • ocx models add openai gpt-5.6-sol / ...-terra / ...-luna (custom rows) → visible in ocx models list-custom, and openai/gpt-5.6-* appear in the catalog.
    • codex exec -m gpt-5.6-luna "…" → ❌ 401 (below).
    • codex exec -m openai/gpt-5.6-luna "…" (namespaced custom row) → ❌ same 401.
  6. Control: ocx restore back to native, then codex exec -m gpt-5.6-luna "…" → ✅ succeeds.

A/B matrix:

Path Command Result
Native codex exec -m gpt-5.6-luna "…" ✅ works
opencodex forward (bare id) codex exec -m gpt-5.6-luna "…" ❌ 401
opencodex forward (custom namespaced id) codex exec -m openai/gpt-5.6-luna "…" ❌ 401

Logs / error output

ERROR: unexpected status 401 Unauthorized: The selected ChatGPT account does not support this model, url: http://127.0.0.1:10100/v1/responses

ocx models live:

gpt-5.5              [native, enabled]
gpt-5.4              [native, enabled]
gpt-5.4-mini         [native, enabled]
gpt-5.3-codex-spark  [native, enabled]

Redacted configuration

Relevant part of ~/.opencodex/config.json:

{
  "providers": {
    "openai": {
      "adapter": "openai-responses",
      "baseUrl": "https://chatgpt.com/backend-api/codex",
      "authMode": "forward"
    }
  },
  "defaultProvider": "openai"
}

Account: plan=plus, subscription 2026-08-22 → 2026-09-22; opencodex reports the main account as healthy, needsReauth=false (email / account id redacted).

Additional observations

Expected behavior

For a Plus account that is genuinely entitled to GPT-5.6, opencodex forwarding should behave like native Codex for gpt-5.6-sol/terra/luna:

  1. ocx models live native rows should include the GPT-5.6 trio.
  2. Requests must not be fail-closed into a 401.
  3. A missing/unconfirmed roster must not be treated as proof that the account is unentitled.

Checks

Activity

  1. coderabbitai commented on Sep 3, 2026

    @coderabbitai
    Contributor
    ⚠️ Possible Duplicate Issue(s)

    📝 Issue Planner

    Check the box below or use the @coderabbitai plan command to generate an implementation plan and prompts that you can use with your favorite coding assistant.

    • Create Plan

    🧪 Issue enrichment is currently in open beta.

    To disable automatic issue enrichment, add the following to your .coderabbit.yaml:

    issue_enrichment:
      auto_enrich:
        enabled: false

    💬 Have feedback or questions? Drop into our discord!

  2. added
    bugSomething isn't working
    account-poolOAuth, credentials, Codex pool, quota, failover, plans
    on Sep 3, 2026
  3. github-actions commented on Sep 3, 2026

    @github-actions
    Contributor

    Issue reopened

    The report now contains the information required by the automated check. Thanks for updating it.

  4. lidge-jun commented on Sep 3, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 64 / 80

    이 이슈는 ChatGPT Plus 계정으로 GPT-5.6(sol/terra/luna)을 네이티브 Codex에서는 쓸 수 있는데, opencodex 2.40.0 포워딩을 타면 401 Unauthorized: The selected ChatGPT account does not support this model 로 막힌다는 보고입니다. 재현 경로가 아주 분명합니다. authMode: forward(openai-responses → chatgpt.com/backend-api/codex), ocx restore back 후 codex exec -m gpt-5.6-luna, 그리고 커스텀 openai/gpt-5.6-* 행까지 같은 401, 네이티브로 되돌리면 성공. ocx models live 에는 게이트 없는 네 줄(gpt-5.5 / gpt-5.4 / gpt-5.4-mini / gpt-5.3-codex-spark)만 보이고 GPT-5.6 삼총사는 빠집니다. ocx models enable 은 잠깐 켜졌다가 다음 카탈로그 동기화에 다시 사라지고, 커스텀 add 로 카탈로그에 올려도 요청 게이트에서 또 막힙니다.

    지금 dev HEAD(1f00ff52b, package 2.41.0) 기준으로 이 증상은 예전에 닫힌 #2886 / #3022 / #3023 과 같은 가족입니다. 계정 게이트 네이티브 모델은 src/codex/catalog/native-models.ts 의 ACCOUNT_GATED_NATIVE_OPENAI_MODELS(gpt-5.6-sol/terra/luna)이고, 권한은 src/codex/model-entitlements.ts 가 계정별 인증 /models 로스터를 캐시한 뒤 granted / denied / unknown 삼상태로 판정합니다. 카탈로그·라우팅 둘 다 granted 만 통과시킵니다(availableAccountGatedNativeModels, entitledCodexAccountIdsForModel). 그래서 로스터가 비어 있거나 미확인이면 live 목록에서 행이 빠지고, 요청 쪽도 fail-closed 로 401이 납니다. 보고에 나온 문장 The selected ChatGPT account does not support this model 은 src/codex/auth-context.ts 에서 Direct/포워드 호출자 권한 검사(isDirectCallerEntitledToCodexModel) 또는 저장된 메인 자격 검사 실패 시 그대로 던지는 메시지입니다.

    2.36~2.38 구간에 이미 여러 겹 고쳤습니다. #2891(실제 client_version 으로 로스터 질의), #3035(게이트 최소 버전을 측정값 0.144.0 으로 올림 — 스냅샷 0.142.2 만 쓰면 업스트림이 게이트 행 없이 200을 주고 그걸 “확인된 거부”로 읽음), #3057(삼상태 권한), #3054(만료된 management entitlement 갱신). model-entitlements.ts 주석에도 “빈 로스터는 확인된 부정이 아니라 unconfirmed” 라고 못 박혀 있고, MEASURED_GATED_CLIENT_VERSION_MINIMUM = "0.144.0" 이 코드에 있습니다. 보고자가 쓰는 Codex CLI 0.153.0 은 그 바닥보다 높아서, 버전 바닥만의 재발은 아닐 가능성이 큽니다. 다만 fail-closed 계약 자체는 HEAD에도 그대로입니다. 로스터 조회가 http-error / timeout / unparseable / parsed-empty 이면 unknown 이고, Direct 경로의 isDirectCallerEntitledToCodexModel 은 === "granted" 만 true 라서 미확인도 401로 떨어집니다. 카탈로그 sync(catalog/sync.ts, server/index.ts 의 availableAccountGatedNativeSlugs)도 같은 스냅샷을 쓰기 때문에 live 목록에서 삼총사가 동시에 사라지는 현상과 딱 맞습니다.

    보고에 적힌 /api/codex-auth/accounts 의 plan: null 은 진단 힌트로는 유용하지만, 원인 자체로 단정하면 안 됩니다. Decision Log 가 plan 라벨로 권한을 추론하지 않기로 했고, 권한의 권위는 인증된 /models 로스터입니다. plan 이 null 이어도 로스터에 sol/terra/luna 가 있으면 granted 가 되어야 하고, plan 이 plus 여도 로스터가 비거나 미확인이면 지금 계약상 숨기고 막습니다. 그래서 이 이슈의 핵심 검증은 “Plus 인지”가 아니라 opencodex 가 그 계정으로 어떤 client_version 을 붙여 /models 를 쳤고, 캐시에 confirmed+models 가 남았는지 입니다. Windows Scoop Codex 0.153.0 + forward + __main__ healthy 조합에서, 런타임 파일의 selectedVersion / 요청 client_version / entitlement 캐시 provenance 를 한 번에 보면 재발인지(미확인을 거부처럼 취급) 아니면 업스트림이 정말 게이트 행을 안 주는지 갈립니다.

    재현 품질은 높습니다. A/B 표, 버전 경계(2.40.0), 네이티브 대조, 커스텀 네임스페이스 시도까지 있고, labels 도 bug + account-pool 로 맞습니다. types.ts/config.ts 스플릿이나 중복 클로즈 대상은 아닙니다. #2886 등과는 “같은 증상 가족”이지만 2.40.0 에서 아직 재현 이라고 명시했으므로 닫힌 이슈에 흡수하기보다, 현재 dev 2.41.0 HEAD 에서 한 번 더 찍어 보는 게 맞습니다. muse_release_train / Meta·Cursor 카탈로그 작업과는 축이 다르고, Codex 계정 게이트·풀 경로의 사용자 체감 버그라 우선순위는 중상입니다.

    라인 - 해당 없음 (이슈 리포트; 패치 없음)

    src/codex/auth-context.ts (Direct/포워드 gated 분기) - isDirectCallerEntitledToCodexModel 이 false 이면 보고와 동일한 401 문구를 던짐. 미확인(unknown)도 false 로 취급됨.
    src/codex/model-entitlements.ts (codexModelEntitlementStateForRoster / isDirectCallerEntitledToCodexModel) - 긍정 증거만 granted. confirmed 아니거나 로스터 부재면 unknown → 요청 경로 fail-closed.
    src/codex/catalog/native-models.ts (ACCOUNT_GATED_NATIVE_OPENAI_MODELS) - sol/terra/luna 가 게이트 게이트. live 에 안 보이면 이 집합이 entitlement 스냅샷에서 granted 가 아니라는 뜻.
    src/codex/catalog/sync.ts / src/server/index.ts (availableAccountGatedNativeSlugs) - 카탈로그·/v1/models 도 같은 스냅샷으로 게이트 행을 걸러서, enable 이 동기화에 지워지는 보고와 일치.
    경로 /api/codex-auth/accounts 의 plan: null - 권한 권위가 아님. 로스터 캐시·client_version·provenance 를 먼저 볼 것.

    메인테이너의 판단이 필요한 지점

    • 보고자에게 2.41.0 / 현재 dev HEAD 재현을 받을지, 아니면 메인테이너가 Windows Plus 계정으로 forward 경로를 직접 찍을지.
    • 로스터가 unconfirmed 일 때 Direct 요청을 계속 fail-closed(현행)로 둘지, “네이티브는 되는데 프록시만 막힘”을 줄이려고 한시적으로 upstream 통과/재시도 정책을 넣을지(턴 낭비·잘못된 계정 노출 트레이드오프).
    • plan: null 이 forward/__main__ 진단 UX 버그로 따로 고칠 가치가 있는지, 아니면 entitlement 로스터 경로만 보면 되는지.

    너의 추천
    bug/account-pool 유지. 보고자에게 opencodex 2.41.0(또는 dev 빌드)에서 같은 A/B를 한 번 더 찍어 달라고 하고, 가능하면 ocx entitlement/management 상태(또는 /api/models + entitlement status)에서 client_version·confirmed·gated slug 포함 여부를 붙여 달라고 하세요. HEAD에서 재현되면 model-entitlements Direct fail-closed + roster provenance 쪽 조사 PR을 열고, 재현 안 되면 2.40.0→2.41.0 회귀 해소로 닫으면 됩니다. #2886/#3022/#3023 에 흡수해 닫지 마세요. 버전 경계가 다릅니다.

    이 댓글은 grok-bot이 작성했습니다

  5. ZhenyuXiao commented on Sep 3, 2026

    @ZhenyuXiao
    Author

    Reproduced on a fresh opencodex 2.41.0 install (same machine, same ChatGPT Plus account, codex-cli 0.153.0):

    • Upgraded via npm install -g --allow-scripts=bun @bitkyc08/opencodex@2.41.0, ocx service repair, then a clean ocx stop / ocx service start so the proxy runs the new package (/healthz reports version: 2.41.0).
    • ocx models live → still only the four non-gated rows (gpt-5.5 / gpt-5.4 / gpt-5.4-mini / gpt-5.3-codex-spark), no gpt-5.6-*.
    • Proxy GET /v1/models → returns 4 native rows, GPT-5.6 trio absent.
    • codex exec -m gpt-5.6-luna "…" → still 401 Unauthorized: The selected ChatGPT account does not support this model.
    • Control: native Codex (opencodex restored) with the same account can use gpt-5.6-luna successfully.

    So this is not the version-floor regression: codex-cli 0.153.0 is well above MEASURED_GATED_CLIENT_VERSION_MINIMUM (0.144.0), yet the entitlement/roster path still leaves the gated slugs unconfirmed and fail-closes on the request. This matches juzijia's residual capture in #2886 (roster at 0.142.2 omits GPT-5.6; 0.144.0+ includes it) — it looks like the roster query that drives the gate is still not using the request/runtime client version (0.153.0) on this path.

    Happy to capture whatever management/entitlement state you want next (e.g. the exact client_version opencodex sends on /codex/models and the cached roster provenance) — tell me which endpoint/log to grab and I'll post a redacted capture.

  6. Veritas-7 commented on Sep 3, 2026

    @Veritas-7
    Contributor

    One additional observation from a local usage-log and macOS power-log review: the 401s were local fail-closed decisions during an unconfirmed roster state, and the native route had no alternate candidate to try.

    Observations

    • On 2026-09-03 from 21:13:45 to 21:14:24 local time, there were 34 terminal 401s across gpt-5.6-luna (28) and gpt-5.6-sol (6). Every record had an empty attempts field, no accountLogLabel, and no firstOutputMs. The recorded error was No eligible Codex account supports this model with errorCode: invalid_api_key.
    • The route record for all 34 was routeKind: native with exactly one eligible candidate: the requested OpenAI model. Thus these requests ended before an upstream model attempt; account refresh, account failover, and model fallback were not entered.
    • This also explains the simultaneous worker impact more precisely than the status code alone. The combo classifier treats 401 and 503 as hop-worthy, but this was not a combo route: native routing does not hop. Each request had one candidate, so there was no replacement path regardless of which status code was returned. The configured subagentModelFallback list has five entries, but that is the quota-oriented thread-spawn path, not this native single-candidate route.
    • The 34 records grouped as follows (3 + 4 + 6 + 15 + 6 = 34): 12–19 ms for three records (consistent with the MODEL_ROSTER_FAILURE_TTL_MS = 15_000 failure-cache window); 6.139–6.750 seconds for four; 7.075–7.718 seconds for six; 7.977–8.037 seconds for 15 (this cluster matches MODEL_ROSTER_TIMEOUT_MS = 8_000); and 656.649–656.675 seconds for six. The six long requests overlap the first sleep interval in the power log: configd: Process interface link status inactive: en0 at 21:13:45.312; powerd: Entering Sleep state due to 'Maintenance Sleep' at 21:14:30.755; and powerd: Updating wake end timestamp at 21:25:25.793. The same interval also contained 502/504 records on other routes.
    • The host then remained in clamshell sleep on battery power until the clamshell state changed to open at 01:42:28. The power log shows repeated roughly 45-second DarkWake-to-sleep cycles while it remained closed, including entries around 21:26, 21:28, 21:29, 21:30, 21:31, 21:32, 21:33, and 21:34. The six 656-second requests therefore represent only the initial sleep interval, not the full interruption.
    • This was not consistent with credential expiry in this capture. There was no GPT-5.6 traffic from 21:14:30 until 01:46:24, and the first subsequent success was at 01:46:24.302. The credential file mtime was 01:45:50.093; we inspected metadata only, not the file contents. The first success therefore followed that mtime by about 34 seconds.
    • A separate 2026-08-31 review found 57 401s with the same error string and empty attempts shape, but the duration profile was different: only four were in the 7–8.2-second range; the 08:00 hour ranged from 103 to 396 seconds (plus one sub-second record), while the 15:00 hour ranged from 0.5 to 30 seconds. We did not establish the same causation.
    • We also observed that a roster timeout can replace a previously confirmed grant cache entry with an unconfirmed-empty entry through boundedCacheSet. This is an observation of the current behavior, not a proposed change.

    Relevance to the design question

    This capture separates two questions. First, fail-fast was appropriate for this particular interruption: the host was unavailable for roughly 4.5 hours, not merely a short network blip. An unlimited transient-retry policy would have left the concurrently running workers occupying slots and repeatedly probing the same unavailable /models path throughout that interval. We observed the interruption and its repeated sleep cycles; we did not run that counterfactual policy, so the slot-occupancy consequence is an implication rather than a separately measured result.

    Second, the resulting failure was classified as a permanent authentication-style 401 even though the route record shows an unconfirmed roster and no upstream attempt. If fail-closed remains in place, this capture shows that user-visible consequence: a native single-candidate request returns locally, and all account/model recovery paths are bypassed. If transient and permanent conditions are treated differently, this capture shows why any transient handling would need to account for long host-sleep intervals rather than assume a short outage. We are not recommending either policy or a code change; these are the observed implications for the decision.

    Reproduction environment

    • opencodex 2.40.0
    • codex-cli 0.151.0
    • Node 22.22.1
    • macOS 26.6.2

    All timestamps above are local time. No credentials, account identifiers, machine identifiers, or file contents are included.

  7. shortFisherman commented on Sep 4, 2026

    @shortFisherman

    Reproduced on opencodex 2.42.0 — main Codex account also reports plan: null and quota: null

    I can still reproduce the same GPT-5.6 entitlement/catalog problem on opencodex 2.42.0 on Windows 11 with a ChatGPT Plus Codex login.

    Control behavior is unchanged:

    • Native Codex / OpenCodex stopped: GPT-5.6 Sol/Terra/Luna are visible and usable.
    • Through OpenCodex: the GPT-5.6 trio is missing from the native catalog.

    There is now an additional account/quota symptom which may help narrow down the failing state path.

    Running:

    ocx account list openai --quota --refresh --json

    returns:

    {
      "accounts": [
        {
          "provider": "openai",
          "type": "codex",
          "id": "__main__",
          "label": "Codex App login",
          "email": "Codex App login",
          "plan": null,
          "active": true,
          "needsReauth": false,
          "priority": 0,
          "paused": false,
          "quota": null
        }
      ],
      "notes": []
    }

    The dashboard therefore no longer shows the 5-hour or weekly quota bars. Instead it shows warnings equivalent to:

    • Incomplete coverage: 1 account excluded
    • 1 account(s) on an uncalibrated plan are counted at the baseline seat weight

    The account itself is still active and does not need reauthentication, and native Codex continues to work with the same ChatGPT Plus login.

    This looks consistent with the existing __main__ account-state problem described in this issue, but now on 2.42.0 and with the additional evidence that both plan metadata and quota windows are absent at the same time as the GPT-5.6 entitlement/catalog failure.

    So the current observed state is:

    opencodex: 2.42.0
    OS: Windows 11
    Account: ChatGPT Plus / Codex App login
    __main__.plan: null
    __main__.quota: null
    needsReauth: false
    active: true
    Native Codex GPT-5.6: works
    OpenCodex GPT-5.6: missing / blocked
    Dashboard 5h + weekly quota: missing
    

    This may be useful for checking whether the /models entitlement roster failure and the WHAM/main-account metadata path share a common upstream credential/account-context problem, even if plan: null itself is not authoritative for GPT-5.6 entitlement.

  8. lidge-jun commented on Sep 5, 2026

    @lidge-jun
    Owner

    Closing as fixed on dev.

    The 401 The selected ChatGPT account does not support this model for GPT-5.6 Sol / Terra / Luna, and their absence from ocx models live, are resolved by #3460 (f3d0edb34, merged 2026-09-04 11:16 UTC — after the last reproduction posted here at 05:52 UTC). On current dev (445742966) ACCOUNT_GATED_NATIVE_OPENAI_MODELS contains only Daybreak (src/codex/catalog/native-models.ts:47), so the roster-gated projection and the request gate in src/codex/auth-context.ts no longer apply to the GPT-5.6 trio at all: they list without a roster and are admitted for any account with a working credential. Pinned by tests/codex-integration/native-model-toggle.test.ts ("the flagship natives list without any roster; only Daybreak still waits for one") and tests/codex-integration/codex-model-entitlements.test.ts.

    The separate plan: null / quota: null observation from @shortFisherman comes from the /backend-api/wham/usage fetch (src/codex/auth-api.ts), which is independent of the model roster; it does not affect the GPT-5.6 gate on current code. If that persists on 2.43.0+, please open a new issue with the redacted ocx account list openai --quota --refresh --json output and the WHAM status/error category so it can be tracked on its own.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    account-poolOAuth, credentials, Codex pool, quota, failover, plansbugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions