Repository navigation
Codex Luna Reserve / gpt-reserve mode disables OpenCodex routed models after 5-hour quota is exhausted #2813
Description
Client or integration
Codex App / Codex model picker with OpenCodex routed models.
Area
Catalog / models / Codex client compatibility.
Version
2.34.0
Operating system
Windows 11 25H2
Summary
After a recent Codex update, when the normal 5-hour Codex quota is exhausted, Codex offers a reserve fallback model (gpt-reserve / Luna Reserve) so the user can continue working.
Once this reserve mode becomes active, other models in the Codex model picker become unavailable and cannot be selected. This also affects models injected/routed by OpenCodex, even though those third-party/provider models do not necessarily consume the exhausted ChatGPT/Codex quota.
This makes OpenCodex routed models effectively unusable from the picker for the rest of the 5-hour quota window.
Current behaviour
Before the 5-hour Codex quota is exhausted:
- OpenCodex routed models are present in the model picker.
- They can be selected normally.
- Requests route through OpenCodex as expected.
After the 5-hour Codex quota is exhausted:
- Codex activates/offers
gpt-reserve(Luna Reserve) as a fallback. - Other models become unavailable in the model picker.
- OpenCodex routed models are also no longer selectable.
The important part is that the reserve/quota gating appears to apply globally to the picker rather than only to native ChatGPT/Codex models.
Expected behaviour
OpenCodex routed models that use independent providers/credentials should remain selectable when the native Codex 5-hour quota is exhausted.
If the Codex client itself performs this availability check before requests reach OpenCodex, it would be useful for OpenCodex to investigate whether there is a compatible catalog representation, alternate selection path, or documented workaround that keeps routed models usable during Luna Reserve mode.
At minimum, OpenCodex should document this as a Codex client compatibility limitation if it cannot be worked around from the proxy/catalog side.
Reproduction
- Configure OpenCodex and sync routed models into Codex.
- Verify that routed models can be selected normally from the Codex model picker.
- Use Codex until the normal 5-hour usage limit is exhausted.
- Observe that Codex offers/activates
gpt-reserve/ Luna Reserve. - Open the model picker again.
- Try to select an OpenCodex routed model.
- The routed model is unavailable / cannot be selected, together with the other non-reserve models.
Why this looks like a compatibility issue
The failure happens at model selection time, so it may be caused by Codex applying subscription-quota availability rules to every catalog entry, including custom/routed OpenCodex entries, before OpenCodex gets a chance to route the request.
That would mean a native ChatGPT quota state is unintentionally disabling models backed by unrelated providers.
Suggested investigation
- Check how the latest Codex client represents the Luna Reserve /
gpt-reservestate in its model catalog and picker. - Determine whether custom OpenCodex catalog entries can opt out of native ChatGPT quota gating.
- Check whether explicitly selecting a routed model by model ID still works even when the picker disables it.
- If direct model selection works, consider documenting/exposing that as a temporary workaround.
- If Codex rewrites or rejects the selected model before the request reaches OpenCodex, document the upstream limitation and, if possible, coordinate an upstream Codex fix.
Additional context
This started after the recent Codex update that introduced/exposed the reserve fallback after the normal 5-hour limit is reached.
I searched the existing OpenCodex issues and did not find a report specifically covering gpt-reserve / Luna Reserve disabling OpenCodex routed models.
Checks
- I searched existing issues.
- I removed credentials and personal data.
- This report distinguishes native Codex quota from independently routed OpenCodex provider models.
Activity
github-actions commentedon Aug 28, 2026
Issue reopened
The report now contains the information required by the automated check. Thanks for updating it.
lidge-jun commentedon Aug 28, 2026
리뷰 · 우선순위 69 / 80
설명
이 이슈는 Codex 앱이 일반 5시간 할당량을 다 쓰면 Luna Reserve(
gpt-reserve)로 넘어가면서, OpenCodex가 넣어 준 라우트 모델까지 피커에서 고를 수 없게 된다는 보고다. 보고자는 Windows 11과 OpenCodex 2.34.0이다. 지금devHEAD는 80e251a4d이고 패키지는 2.35.0이다. 방금 들어온 #2815는 Windows에서 coordinator adoption 파일을 읽기 전용으로 열어 fsync하다가 EPERM이 나던 수정이다. 피커나 할당량과는 관계가 없다.지금 카탈로그 동기화는 ChatGPT 5시간 할당량을 보고 줄을 숨기지 않는다.
src/codex/catalog/sync.ts의deriveEntry는 라우트 모델에visibility를list로 찍는다. 템플릿이 없으면supported_in_api도 true로 둔다.src/codex/catalog/metadata.ts의applyNativeVisibility는 네이티브 줄만disabledModels나 계정 숨김으로hide한다. 슬래시가 있는 라우트 슬러그는 여기서 건드리지 않는다.src/codex/catalog/provider-fetch.ts의filterCatalogVisibleModels도disabledModels와selectedModels만 본다. 5시간 창 값인shortPercent는 이 세 곳에 없다.5시간 창 자체는
src/codex/quota.ts에 이미 있다.isCodexQuotaExhausted는shortPercent가 100이면 그 계정을 소진으로 본다. 이건 라우팅과 풀 전환(#1791)용이다.src/codex/subagent-model-fallback.ts의isNativeModelQuotaExhausted도 스폰 자식 모델을 바꿀 때만 쓴다. 둘 다 Codex 앱 피커를 잠그지 않는다. OpenCodex 카탈로그에gpt-reserve나 Luna Reserve 슬러그도 없다. 네이티브는gpt-5.6-sol,gpt-5.6-terra,gpt-5.6-luna다.그래서 지금 코드만 보면, 피커가 Reserve만 남기는 동작은 OpenCodex가 카탈로그를 다시 써서 생기는 일이 아닐 가능성이 크다. Codex 앱이 5시간 소진을 보고 피커 전체를 Reserve 전용으로 바꾸는 쪽에 가깝다. 프록시가 요청을 받기 전에 클라이언트에서 막히면,
visibility를list로 유지해도 소용이 없다. 아직 확인이 필요하다. Reserve가 켜진 뒤models.json/opencodex-catalog.json이 바뀌었는지,config.toml의model에 라우트 슬러그를 직접 넣으면 요청이 OpenCodex까지 오는지부터 봐야 한다.#1711은 크레딧 0인 줄을 회색으로 만들자는 기능 요청이라 축이 다르다. #2706은 Luna에 effort를 강제로 낮추는 다른 버그다. types.ts/config.ts 스플릿에 새 설정 키를 지금 넣으면 그 캠페인에 쓸려 가니, 확인 전에는 키를 추가하지 마라. preview 배포도 이 이슈와 상관없다.
라인 311 (
deriveEntryvisibility = list) - 라우트 줄은 5시간 소진과 상관없이 피커에 남도록 찍힌다. 여기서 숨기는 코드는 없다.라인 378 (템플릿 없는 폴백
supported_in_api: true) - API 노출도 할당량과 무관하다. 피커 잠금의 원인이 되기 어렵다.경로
applyNativeVisibility(src/codex/catalog/metadata.ts441-461) - 네이티브만disabledModels로 hide 한다. 슬래시 라우트 슬러그는 continue로 빠져나간다.경로
filterCatalogVisibleModels(src/codex/catalog/provider-fetch.ts1634) -disabledModels와selectedModels만 본다.shortPercent를 읽지 않는다.경로
isCodexQuotaExhausted(src/codex/quota.ts115-129) - 5시간 창은 라우팅/풀 전환용이다. 카탈로그 visibility를 바꾸지 않는다.경로
gpt-reserve/ Luna Reserve - 현재 카탈로그와 네이티브 슬러그 목록에 없다. 클라이언트 전용 모드일 가능성이 크다.경로 재현 - Reserve 켜기 전후 카탈로그 덤프와,
config.toml에 라우트 슬러그를 직접 넣었을 때 프록시 로그가 있는지 아직 없다.메인테이너의 판단이 필요한 지점
너의 추천
이슈는 열고, 코드 PR은 지금 받지 마라. 먼저 Reserve가 켜진 뒤 카탈로그 파일이 실제로 바뀌는지와,
config.toml의model에 라우트 슬러그를 넣으면 요청이 OpenCodex에 도달하는지를 확인해라. 카탈로그는 그대로인데 피커만 잠기면 업스트림 한계로 적고 문서화해라. 카탈로그가 같이 줄면 그때shortPercent가 visibility에 섞인 경로를 찾아라. 새 설정 키는 넣지 마라.이 댓글은 grok-bot이 작성했습니다
lidge-jun commentedon Aug 28, 2026
Investigated this again from source on current
dev, and I could not find an OpenCodex-side gate that would disable routed models when Reserve activates. Recording what was ruled out, since a bare "cannot reproduce" is not much use to you.Checked and excluded:
visibility: "list"; native visibility logic explicitly skips namespaced routed entries.disabledModelsand each provider'sselectedModels. It never consults quota.shortPercentexhaustion is confined to native Codex account selection and does not reach provider routing.provider/modelrequest routes straight to the configured provider without consulting Codex quota at all.gpt-reserveand "Luna Reserve" appear nowhere in the OpenCodex source, nor in the publicopenai/codexsource.Two related fixes landed during this work but neither can explain your symptom:
a52d00a6eonly skips failover candidates inside the native account pool, and #2858 (676a3c03a) retries automatic compaction through a routed target — that runs only after a request reaches OpenCodex, so it cannot re-enable a picker row the client has already greyed out.That points to a Codex App-side Reserve gate, which OpenCodex cannot see or influence. To pin it down we would need, from an account actually in Reserve mode: before/after dumps of
opencodex-catalog.jsonandmodels_cache.json(model/provider/status fields are enough — please omit tokens), and the result of setting the routed model slug directly inconfig.tomlrather than picking it in the UI, plus whether any request then appears in the OpenCodex request log. If a request never arrives, the gate is client-side and this issue belongs upstream.Leaving this open pending that evidence rather than closing it as unreproducible.
lidge-jun commentedon Aug 29, 2026
PR #2862 on
devfixes a real defect found while investigating this — routed catalog rows were carrying native eligibility metadata they have no business carrying. Whether that is your Reserve-mode failure is not established, and this stays open.What changed
Two problems, both in how a routed catalog row gets built:
Template selection could pick an ineligible native row. Three sites chose a native template to base a routed row on, using a lookup that accepted any native row at all. They now use a roster-restricted lookup that only considers supported models.
Notably the four validity checks that use the same permissive lookup were deliberately left alone. They answer a different question — "is this catalog usable at all" — and narrowing them would reject a valid catalog whose only native row is a new one, falling back to stale data. There is now a regression test guarding that distinction, because the two contracts share one function and it would be easy to unify them wrongly.
Five eligibility fields leaked onto routed rows.
supported_in_apiis now forced true andavailable_in_plans,minimal_client_version,availability_nux, andupgradeare dropped for routed rows. The sanitizing happens in the strict-field pass rather than the normalizer, so rows that were preserved from a previous catalog or came from elsewhere are covered too — not just freshly normalized ones.Both are routed-only. Native rows keep their metadata untouched.
What this does not establish
That this is what disables your routed models under Reserve. The mechanism is plausible — a routed row carrying plan-gating metadata is exactly the kind of thing a client would use to hide a model once a quota window closes — but we could not observe the app's behavior under Reserve. The docs note added for this says so explicitly rather than implying it is solved.
What Codex does with these fields. That is client-side and closed to us. We can only stop sending metadata that should not be there.
What would confirm it
If you can reproduce after the next release:
available_in_plansor a non-truesupported_in_api.gpt-reservediffers from ordinary quota exhaustion for you, since only the former was reported.Documentation for the limitation is in
docs-site/under "Native quota fallback limitation", in English and all seven translated locales, each stating that app behavior under Reserve is unverified.fix(codex): keep native eligibility metadata off routed catalog rows (#…
Tariolle commentedon Aug 30, 2026
I have the exact same bug and my OpenCodex is up to date, when the Luna Reserve kicks in the Codex Desktop UI doesn't show me any model except Luna, which makes OpenCodex effectively useless until I get my 5 hours limit back...
lidge-jun commentedon Aug 31, 2026
@Tariolle Thank you — this changes the status of the issue, so I want to be explicit about what your report establishes.
What is now different. My earlier comment recorded that I could not find an OpenCodex-side gate that disables routed models when Reserve activates, and #2862 landed a real defect found while looking (routed catalog rows carrying native eligibility metadata they should not carry). The important detail: #2862 shipped in
v2.36.0— I confirmed withgit describe --tags --contains 124a2b148→v2.36.0^2~88. So if you are on an up-to-date install, you already have that fix and are still seeing the symptom.That means #2862 was not the cause of what you and @Wujerry are hitting. Two independent reporters, one of them on a build that already contains the candidate fix, is no longer a "cannot reproduce" situation. I am treating this as an open, reproducible defect rather than an unconfirmed one.
What would move this fastest. Your screenshot shows the picker collapsed to Luna only, which is the outcome; I need the catalog state that produced it. On the affected install, while Reserve is active:
The specific question those answer: are the routed rows missing from what OpenCodex serves, or are they present in the response and the Codex client is filtering them out on its side? Those are different bugs with different fixes, and the picker screenshot cannot distinguish them. If the rows are present in
/v1/modelswhile the picker shows only Luna, the fault is downstream of the proxy and I need to look at how Reserve mode rewrites the client-side catalog — which is a path I have not audited yet.Redact account identifiers freely; I only need ids and visibility fields.
Reopening the investigation on this. Sorry it took a second reporter to get here — the earlier "ruled out" list was accurate about what I checked, and incomplete about what was actually happening.
lidge-jun commentedon Aug 31, 2026
Triaged in the 2026-08-31 bug round and kept open deliberately. This is one of the few we could not resolve from the tree, and it is worth saying precisely why rather than leaving it to age.
What we checked. No quota value participates in routed visibility anywhere on
dev:deriveEntrywritesvisibility: "list"(src/codex/catalog/sync.ts:311)applyNativeVisibilityskips slash-routed slugs (src/codex/catalog/metadata.ts:441)filterCatalogVisibleModelsreads onlydisabledModelsandselectedModels(src/codex/catalog/provider-fetch.ts:1692)isCodexQuotaExhaustedis pool/routing only (src/codex/quota.ts:115)There is no OpenCodex Reserve gate to fix. #2862 (
124a2b148) already stripsavailable_in_plansand forcessupported_in_api: trueon routed rows, and a second reporter still saw Luna-only on a build containing it. So one blind catalog-field change has already been tried and did not work; a second guess would be guessing harder, not better.Why we cannot close it either. A picker screenshot cannot distinguish "the proxy never advertised the row" from "the client filtered a row the proxy did advertise", and those two have opposite fixes. The docs already record the client gate as unverified (
docs-site/src/content/docs/guides/codex-app-models.md:113).What would unblock this, from an account actually in Reserve at the time:
ocx --versionGET /v1/models— the raw id listGET /api/models—{id, visibility, opencodex_catalog_kind}per rowmodel = "provider/slug"set inconfig.toml, whether a request produces a proxy request-log entry at allItem 4 is the decisive one: a log entry means the proxy served it and the client hid it; no entry means the request never arrived. Everything else follows from that.
docs(codex): explain why routed models are gated during reserve mode (#…
lidge-jun commentedon Sep 1, 2026
Documented in #3202 (merged to
devas 59449fa).Root cause, verified against the installed Codex desktop app renderer bundle (2026-08-31 build): the reserve gate is entirely client-side and never looks at the model catalog.
backend-api/wham/usagepoll returnsrate_limit_upsell.banner_type === "luna_reserve",rate_limit.allowed === false, andadditional_rate_limits[]contains{ limit_name: "gpt-reserve", rate_limit.allowed: true }.modelSettings.modeltogpt-reserveand rewrites any other pick back to it (setModelAndReasoningEffortForNextTurn(reserveActive && model === "gpt-reserve" ? original : model, ...)and the picker collapses to the reserve entry). This happens before any request leaves the app, so aconfig.tomlmodel =value is overridden the same way — that route is not a workaround.codex-rsonly carriesrate_limit_reached_type/x-codex-rate-limit-reached-type; the Luna Reserve gating lives in the Electron app.opencodex routed rows are still published with
visibility: "list"and no quota value participates in catalog filtering; the proxy side is correct. The docs now state this plainly and point to the paths that do work while the window is exhausted:ocx claude,ocx access test <model> --protocol responses, or any direct/v1client.Closing as documented; no proxy-side change can lift a gate the client applies to itself.
github-actions commentedon Sep 1, 2026
Automated translation bookkeeping — detected language: English.
fix(codex): keep native eligibility metadata off routed catalog rows (l…
docs(codex): explain why routed models are gated during reserve mode (l…
fix(codex): keep native eligibility metadata off routed catalog rows (l…
docs(codex): explain why routed models are gated during reserve mode (l…