jlcodes99/cockpit-tools · warning

CODEX_PENDING_OAUTH_ACCOUNT

CODEX_PENDING_OAUTH_ACCOUNT

Error message

CODEX_PENDING_OAUTH_ACCOUNT

What it means

refreshQuota refuses to call the backend for Codex accounts that are still in the pending-OAuth state (isCodexPendingOAuthAccount), throwing CODEX_PENDING_OAUTH_ACCOUNT. Quota cannot be refreshed until the OAuth flow completes and the account has real tokens.

Solutions

  1. Complete the OAuth authorization flow for the account before refreshing quota
  2. Check isCodexPendingOAuthAccount(account) in the UI and disable/defer quota refresh
  3. Re-trigger the account import/OAuth flow if it stalled
  4. Remove and re-add the account if the pending state is permanently stuck

Example fix

// before
await store.refreshQuota(accountId);
// after
const account = store.accounts.find(a => a.id === accountId);
if (account && !isCodexPendingOAuthAccount(account)) {
  await store.refreshQuota(accountId);
}
Defensive patterns

Strategy: type-guard

Validate before calling

const account = store.accounts.find(a => a.id === accountId);
if (account && isCodexPendingOAuthAccount(account)) {
  // defer quota refresh until OAuth completes
}

Type guard

function isRefreshable(a?: CodexAccount): boolean {
  return !!a && !isCodexPendingOAuthAccount(a);
}

Try / catch

try {
  await refreshQuota(accountId);
} catch (e) {
  if ((e as Error).message === 'CODEX_PENDING_OAUTH_ACCOUNT') {
    // prompt user to finish OAuth authorization
  }
}

Prevention

When it happens

Trigger: Calling refreshQuota(accountId) for an account whose state is pending OAuth (imported mid-OAuth, OAuth flow started but never completed, or an account still awaiting authorization).

Common situations: User imported an account but never finished the browser OAuth consent; OAuth callback failed silently; account list refreshed mid-authorization and UI attempted a quota refresh.

Related errors


AI-assisted analysis of jlcodes99/cockpit-tools@1ed8b77992 (2026-09-05). Data as JSON: /api/errors/1719ab4fb33e578d. Report an issue: GitHub.

Appendix: source

Thrown at src/stores/useCodexAccountStore.ts:388

    });
    await emitAccountsChanged({
      platformId: 'codex',
      reason: 'delete',
    });
    const nextCurrentAccountId = get().currentAccount?.id ?? null;
    if (previousCurrentAccountId !== nextCurrentAccountId) {
      await emitCurrentAccountChanged({
        platformId: 'codex',
        accountId: nextCurrentAccountId,
        reason: 'delete',
      });
    }
  },

  refreshQuota: async (accountId: string) => {
    const account = get().accounts.find((item) => item.id === accountId);
    if (account && isCodexPendingOAuthAccount(account)) {
      throw new Error('CODEX_PENDING_OAUTH_ACCOUNT');
    }
    try {
      return await codexService.refreshCodexQuota(accountId);
    } finally {
      await get().fetchAccounts();
      await get().fetchCurrentAccount();
    }
  },

  refreshSubscriptionInfo: async (accountId: string) => {
    const account = await codexService.refreshCodexSubscriptionInfo(accountId);
    await get().fetchAccounts();
    await get().fetchCurrentAccount();
    return account;
  },

  refreshAllQuotas: async () => {
    const successCount = await codexService.refreshAllCodexQuotas();

View on GitHub (pinned to 1ed8b77992)