openai / openai/codex-plugin-cc

[BUG] /codex:setup reports loggedIn:false when shared broker is busy; getCodexAuthStatus missing direct-fallback

Open
#342 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
JavaScript
Stars
33.3k
Forks
2.3k
PR merge metrics
No merged PRs in 30d

Description

Description

/codex:setup (and any other code path that calls getCodexAuthStatus) intermittently reports loggedIn: false with detail: "Shared Codex broker is busy.", even when codex login status shows the user is logged in and the underlying CLI works fine.

The misreport persists across new Claude Code sessions until the broker process is killed or the broker session state is wiped — which is confusing because the user sees "you're not logged in" right after a successful !codex login.

Root cause

In plugins/codex/scripts/lib/codex.mjs, getCodexAuthStatus connects with reuseExistingBroker: true:

https://github.com/openai/codex-plugin-cc/blob/main/plugins/codex/scripts/lib/codex.mjs#L831-L863

If the shared broker is currently servicing another request (activeRequestSocket set), it returns the JSON-RPC BUSY error (code: -32001). getCodexAuthStatusFromClient swallows that exception into buildAuthStatus({ loggedIn: false, detail: error.message }), and the outer getCodexAuthStatus propagates that as the final result.

The sibling helper withAppServer in the same file already handles this scenario by retrying with disableBroker: true:

https://github.com/openai/codex-plugin-cc/blob/main/plugins/codex/scripts/lib/codex.mjs#L607-L636

getCodexAuthStatus simply doesn't implement that fallback.

Reproduction

  1. Run any command that spawns the shared broker and holds it busy with a long-running RPC call (e.g. start /codex:rescue or any task/start).
  2. While that's still running, run /codex:setup in another tool/window or programmatically.
  3. Observe auth.loggedIn: false with auth.detail: "Shared Codex broker is busy." even though credentials are valid.

A reliable synthetic repro (no real codex needed): start a tiny node TCP server on a named pipe / unix socket that responds to every JSON-RPC id-bearing request with {error:{code:-32001,message:"Shared Codex broker is busy."}}, point CODEX_COMPANION_APP_SERVER_ENDPOINT at it, then run node scripts/codex-companion.mjs setup --json. Without a fallback you see loggedIn:false; with a disableBroker:true retry path you see the real loggedIn:true.

Suggested fix

Mirror what withAppServer already does. Roughly:

export async function getCodexAuthStatus(cwd, options = {}) {
  const availability = getCodexAvailability(cwd);
  if (!availability.available) { /* unchanged */ }

  const brokerRequested =
    Boolean((options.env ?? process.env)[BROKER_ENDPOINT_ENV]) ||
    Boolean(loadBrokerSession(cwd)?.endpoint);

  let client = null;
  try {
    client = await CodexAppServerClient.connect(cwd, {
      env: options.env,
      reuseExistingBroker: true
    });
    return await getCodexAuthStatusFromClient(client, cwd);
  } catch (error) {
    const brokerAttempted = client?.transport === "broker" || brokerRequested;
    const shouldRetryDirect =
      brokerAttempted &&
      (error?.rpcCode === BROKER_BUSY_RPC_CODE ||
       error?.code === "ENOENT" ||
       error?.code === "ECONNREFUSED");

    if (client) { await client.close().catch(() => {}); client = null; }

    if (shouldRetryDirect) {
      try {
        client = await CodexAppServerClient.connect(cwd, {
          env: options.env,
          disableBroker: true
        });
        return await getCodexAuthStatusFromClient(client, cwd);
      } catch (directError) {
        return buildAuthStatus({
          loggedIn: false,
          detail: directError instanceof Error ? directError.message : String(directError),
          source: "app-server"
        });
      }
    }

    return buildAuthStatus({
      loggedIn: false,
      detail: error instanceof Error ? error.message : String(error),
      source: "app-server"
    });
  } finally {
    if (client) { await client.close().catch(() => {}); }
  }
}

This also requires removing the inner try/catch from getCodexAuthStatusFromClient so the underlying RPC error (with rpcCode) propagates up; otherwise it always gets wrapped into a "logged out" status before the outer can inspect it.

Happy to send a PR if useful.

Environment

  • codex-plugin-cc: 1.0.4 (latest as of this report)
  • Codex CLI: 0.132.0
  • Node: 24.15.0
  • OS: Windows 11 (also affects the unix-socket transport on macOS/Linux — the underlying logic is platform-independent)

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in plugins/codex/scripts/lib/codex.mjs, reading getCodexAuthStatus, getCodexAuthStatusFromClient, and the sibling withAppServer fallback. Reproduce the busy-broker case with the synthetic JSON-RPC server or by running /codex:setup during a long-running request. Done means a busy shared broker falls back to a direct connection and reports the actual login status rather than loggedIn:false.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
authentication, cli
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.