{"record":{"id":"f4bffcd99433031d","repo":"decolua/9router","slug":"failed-to-fetch-codex-usage-error-message","errorCode":null,"errorMessage":"Failed to fetch Codex usage: ${error.message}","messagePattern":"Failed to fetch Codex usage: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"open-sse/services/usage/codex.js","lineNumber":134,"sourceCode":"    const reviewRateLimit = getCodexReviewRateLimit(data);\n    const sparkRateLimit = getCodexSparkRateLimit(data);\n    const availableResetCredits = Math.max(0, toFiniteNumber(data.rate_limit_reset_credits?.available_count, 0));\n    const quotas = {};\n\n    appendCodexQuotaWindows(quotas, \"\", normalRateLimit);\n    appendCodexQuotaWindows(quotas, \"review\", reviewRateLimit);\n    appendCodexQuotaWindows(quotas, \"spark\", sparkRateLimit);\n\n    return {\n      plan: data.plan_type || data.summary?.plan || \"unknown\",\n      limitReached: getCodexRateLimitBody(normalRateLimit)?.limit_reached || false,\n      reviewLimitReached: getCodexRateLimitBody(reviewRateLimit)?.limit_reached || false,\n      sparkLimitReached: getCodexRateLimitBody(sparkRateLimit)?.limit_reached || false,\n      resetCredits: { availableCount: availableResetCredits },\n      quotas,\n    };\n  } catch (error) {\n    throw new Error(`Failed to fetch Codex usage: ${error.message}`);\n  }\n}\n\nexport async function getCodexRateLimitResetCredits(accessToken, proxyOptions = null, providerSpecificData = null) {\n  if (!accessToken) {\n    throw new Error(\"No Codex access token available. Please re-authorize the connection.\");\n  }\n\n  const accountId = getCodexAccountId(providerSpecificData);\n  const headers = {\n    \"Authorization\": `Bearer ${accessToken}`,\n    \"Accept\": \"application/json\",\n    \"OpenAI-Beta\": \"codex-1\",\n    \"originator\": \"codex_cli_rs\",\n  };\n  if (accountId) headers[\"ChatGPT-Account-ID\"] = accountId;\n\n  const response = await proxyAwareFetch(CODEX_CONFIG.resetCreditsUrl, {","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/open-sse/services/usage/codex.js#L116-L152","documentation":"getCodexUsage aggregates Codex rate-limit and quota information from ChatGPT backend endpoints. Any failure inside the aggregation — network error, bad token, unexpected response shape — is wrapped and rethrown as this error with the original message appended. It is a catch-all wrapper, so the inner message carries the real cause.","triggerScenarios":"Any underlying failure while fetching Codex usage: fetch rejects (network/DNS/proxy), access token is expired (401/403), required account id missing, or rate-limit body shapes are missing causing a parse error.","commonSituations":"ChatGPT/Codex OAuth token expired and not refreshed; codex account data (account_id) absent from providerSpecificData; backend endpoint changed; connectivity issues through a proxy.","solutions":["Read the inner error.message after the colon — it names the real failure (timeout, 401, JSON parse)","Re-authorize the Codex/ChatGPT connection to get a fresh access token","Ensure providerSpecificData contains the Codex account id expected by getCodexAccountId","Retry on transient network errors; verify proxy configuration if behind a corporate proxy"],"exampleFix":"// before\nconst usage = await getCodexUsage(accessToken, proxyOptions, data);\n// after\nlet usage;\ntry {\n  usage = await getCodexUsage(accessToken, proxyOptions, data);\n} catch (e) {\n  if (/re-authorize|401|403/i.test(e.message)) {\n    accessToken = await refreshCodexToken(connection);\n    usage = await getCodexUsage(accessToken, proxyOptions, data);\n  } else throw e;\n}","handlingStrategy":"try-catch","validationCode":"if (!accessToken) {\n  throw new Error('Codex connection not authorized; skipping usage fetch.');\n}\nif (!getCodexAccountId(providerSpecificData)) {\n  throw new Error('Codex account id missing from providerSpecificData.');\n}","typeGuard":"function codexReady(token, data) {\n  return typeof token === 'string' && token.length > 0 &&\n    Boolean(data && typeof data.accountId === 'string' && data.accountId);\n}","tryCatchPattern":"try {\n  usage = await getCodexUsage(accessToken, proxyOptions, data);\n} catch (e) {\n  const inner = e.message.replace(/^Failed to fetch Codex usage:\\s*/, '');\n  if (/401|403|re-authorize/i.test(inner)) { accessToken = await refreshCodexToken(conn); usage = await getCodexUsage(accessToken, proxyOptions, data); }\n  else if (/fetch|network|timeout/i.test(inner)) { await backoff(); usage = await getCodexUsage(accessToken, proxyOptions, data); }\n  else throw e;\n}","preventionTips":["Always read the inner message after the wrapper prefix — it names the true cause","Refresh Codex tokens proactively before expiry","Populate providerSpecificData with the Codex account id at connection time","Handle dashboard display of usage errors gracefully instead of crashing the panel"],"tags":["network","codex","openai","wrapper"],"backgroundTag":"http-error-response","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}