Skip to content

Codex Desktop hides all opencodex-routed models once Luna Reserve is active; gpt-reserve forwarded natively and rejected #4940

Closed

Description

@Rizek000

Client or integration

Codex App

Area

Catalog / models

Summary

With opencodex injected as the Codex Desktop provider, all opencodex-routed models disappear from the Desktop model picker once the ChatGPT allowance is exhausted and Luna Reserve becomes active. The only request Desktop still sends, gpt-reserve, is forwarded natively by the proxy and rejected upstream, so no model is usable until the ChatGPT reset.

Expected: opencodex-routed models remain selectable and usable in Desktop while the ChatGPT allowance is exhausted, or ocx status / ocx doctor states that the injected models are hidden while Reserve is active. If Desktop can only emit gpt-reserve in this state, the proxy offers a way to keep an independently credentialed route usable.

Reproduction

Reproducible: always. Also reproduced after updating from 2.55.0-preview.20260914 to 2.58.0 and restarting Desktop.

  1. ocx ensure; confirm anthropic and custom models appear in the Desktop picker while ChatGPT quota is available.
  2. Use Codex until the ChatGPT weekly allowance reaches 100%. The Desktop widget switches to "Luna Reserve · 100% remaining".
  3. Open the Desktop model picker. Only GPT-5.6 Luna is listed; all opencodex-routed models are gone.
  4. Send a message with GPT-5.6 Luna. Desktop shows "You've hit your usage limit. Add credits to continue, or try again at Sep 19, 2026, 2:20 PM."

Version

2.58.0 (npm latest), bundled Bun 1.4.0, launchd service on loopback port 10100. Codex Desktop 26.911.61220 (build 9647), bundled codex-cli 0.155.0-alpha.2.6.

Operating system

macOS 26.6 (25G5057c), arm64

Provider and model

openai (ChatGPT Pro account pool) / gpt-reserve, native route. Default provider anthropic (OAuth) / claude-fable-5-1; one custom openai-responses provider. routing=opencodex-local, multi_agent_mode: v1, codexDesktopAuthless not enabled.

Logs or error output

ocx logs entry for the failing send, 2026-09-17 21:34:26 CEST:

429  openai-<acct>/gpt-reserve  3915ms  routeKind=native
errorCode=rate_limit_exceeded  upstreamError="The usage limit has been reached"

The 264 Desktop requests for gpt-5.6-luna the same day were shadow-rewritten to claude-sonnet-5 (shadowCallRewrittenFrom), so Reserve traffic only exists as gpt-reserve. ocx doctor reports the proxy healthy and the 2.58.0 CLI matching the running proxy. Quota cache for the main account: weeklyPercent 100, weeklyResetAt 2026-09-19 14:20 CEST, resetCredits 0.

Screenshots and supporting files

Screenshots of the usage widget and the collapsed picker will be attached in a comment.

Redacted configuration

Stock ocx ensure injection: openai_base_url pointed at the loopback proxy, model_catalog_json from ~/.codex/opencodex-catalog.json. No codexDesktopAuthless, no codexAccountNamespaces.

Checks

  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.

Activity

  1. github-actions commented on Sep 17, 2026

    @github-actions
    Contributor

    Issue reopened

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

  2. added
    bugSomething isn't working
    catalogModel catalog, slugs, visibility, routed entries
    on Sep 17, 2026
  3. Rizek000 commented on Sep 17, 2026

    @Rizek000
    Author
    Image Image
  4. guilhermemarketing commented on Sep 17, 2026

    @guilhermemarketing

    We investigated this exact failure mode today in ChatGPT Desktop (macOS ARM64, Electron 26.911.61220) and identified both the root cause and a robust, working workaround that opencodex could easily integrate natively.

    1. Root Cause Breakdown

    There are actually two distinct layers of locking in the Desktop app when ChatGPT quota is depleted:

    1. UI Model Picker Lockdown & gpt-reserve emission:

      • When the primary allowance reaches 100%, /backend-api/wham/usage returns rate_limit: { allowed: false } and rate_limit_upsell: { banner_type: 'luna_reserve' }.
      • The Desktop React state sets isLunaReserveActive = true, which forcefully overrides the active model to gpt-reserve (labeled as 🌙 GPT-5.6 Luna) and collapses/hides the custom model dropdown.
      • When the user sends a message, Desktop emits model: "gpt-reserve". Since opencodex forwards gpt-reserve natively to OpenAI (https://chatgpt.com/backend-api/codex/responses), OpenAI rejects it with 429 usage_limit_reached once reserve capacity is zero.
    2. Hard Composer Lockout (Send Button Disabled):

      • Once Luna Reserve / account credits are completely exhausted (0 credits, rate_limit_reached_type !== null), the Recoil atom in Desktop (Cro/wro) transitions to hardBlocked: true.
      • This causes the composer components (f9 -> Exr -> plr) to enforce submitDisabled: true, completely disabling the send button (aria-label="Enviar" / Send) and rendering the blocking modal ("You've run out of usage for Codex...").

    2. The Architectural Discovery in Electron (main-*.js)

    In the Desktop Electron main process:

    • The base URL resolver checks process.env.CODEX_API_BASE_URL:
      function vw(e) {
        let t = process.env.CODEX_API_BASE_URL;
        return t && t.trim().length > 0 ? t.replace(/\/+$/, '') : ...
      }
    • Crucially, localhost:8000 is explicitly whitelisted in isDesktopAuthAllowedUrl(e) alongside native endpoints, meaning Desktop happily attaches OAuth Bearer tokens, DeviceCheck headers, and account IDs when talking to http://localhost:8000/backend-api!

    3. The Working Solution

    We implemented a two-part solution that completely restores full functionality:

    Part A: Transparent Unblocker Proxy on port 8000

    A lightweight local proxy on 127.0.0.1:8000 transparently passes through all endpoints to https://chatgpt.com, except GET /backend-api/wham/usage:

    • When intercepting /wham/usage, it decompresses gzip/br/deflate, and overrides:
      {
        "rate_limit": {
          "allowed": true,
          "limit_reached": false,
          "primary_window": { "used_percent": 0 }
        },
        "rate_limit_reached_type": null,
        "rate_limit_upsell": null,
        "credits": {
          "has_credits": true,
          "unlimited": true,
          "balance": "1000"
        }
      }
    • With CODEX_API_BASE_URL="http://localhost:8000/backend-api" set in LaunchServices (launchctl setenv), Desktop never enters hardBlocked: true. The upsell modal disappears, and the composer send button remains fully enabled.

    Part B: Model Redirection in OpenCodex

    To handle cases where Desktop forces gpt-reserve or gpt-5.6-luna:

    • In ~/.opencodex/config.json, configure model redirects:
      "blockedModelRedirects": {
        "gpt-reserve": "deepseek/deepseek-flash",
        "gpt-5.6-luna": "deepseek/deepseek-flash",
        "gpt-5-6-pro": "deepseek/deepseek-flash"
      }
    • When Desktop sends a prompt targeting gpt-reserve, the opencodex router rewrites it to your configured provider (e.g. deepseek/deepseek-flash or anthropic/claude-sonnet-5), executing the prompt with full reasoning and returning HTTP 200 to Desktop!

    4. Recommendation for OpenCodex Upstream

    @lidge-jun Opencodex could incorporate this directly so users don't need manual workarounds:

    1. Built-in gpt-reserve Routing:
      In src/router.ts (or src/codex/luna-reserve-hop.ts), if upstream returns isLunaQuotaRejection(429) or if defaultProvider !== 'openai', optionally redirect gpt-reserve to the configured default provider instead of failing with 429.
    2. Native ocx desktop unblock / Port 8000 Listener:
      Opencodex could bind a secondary listener on 127.0.0.1:8000 (or multiplex via CODEX_API_BASE_URL) to mock /wham/usage with allowed: true. A CLI command like ocx desktop-bypass on/off could automatically manage launchctl setenv CODEX_API_BASE_URL and LaunchAgent lifecycles.

    Happy to provide a PR or detailed code samples for the unblocker service if the maintainers would like to integrate it into ocx!

  5. Rizek000 commented on Sep 17, 2026

    @Rizek000
    Author
  6. Rizek000 commented on Sep 17, 2026

    @Rizek000
    Author

    @lidge-jun looks like you are already on top of this but can you include this issue in you threads?

  7. lidge-jun commented on Sep 18, 2026

    @lidge-jun
    Owner

    Fixed on dev by #4968 at 277291f — local refusal when codexDesktopAuthless is unset so gpt-reserve is no longer forwarded as a native model into an unhelpful upstream 429.

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

    bugSomething isn't workingcatalogModel catalog, slugs, visibility, routed entries

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions