{"record":{"id":"ffd65aeab8730efe","repo":"decolua/9router","slug":"data-message-data-error-data-detail","errorCode":null,"errorMessage":"${data?.message || data?.error || data?.detail || `Codex reset credits API unavailable (${response.status}).`}","messagePattern":"\\$\\{data\\?\\.message \\|\\| data\\?\\.error \\|\\| data\\?\\.detail \\|\\| `Codex reset credits API unavailable \\(\\$\\{response\\.status\\}\\)\\.`\\}","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"open-sse/services/usage/codex.js","lineNumber":166,"sourceCode":"    \"originator\": \"codex_cli_rs\",\n  };\n  if (accountId) headers[\"ChatGPT-Account-ID\"] = accountId;\n\n  const response = await proxyAwareFetch(CODEX_CONFIG.resetCreditsUrl, {\n    method: \"GET\",\n    headers,\n  }, proxyOptions);\n\n  let data = null;\n  try {\n    data = await response.json();\n  } catch {\n    data = null;\n  }\n\n  if (!response.ok) {\n    const message = data?.message || data?.error || data?.detail || `Codex reset credits API unavailable (${response.status}).`;\n    throw new Error(message);\n  }\n\n  const credits = Array.isArray(data?.credits) ? data.credits : [];\n  return {\n    availableCount: Math.max(0, toFiniteNumber(data?.available_count ?? data?.availableCount, 0)),\n    credits: credits.map((credit) => ({\n      status: String(credit?.status || \"unknown\"),\n      grantedAt: toIsoDate(credit?.granted_at ?? credit?.grantedAt),\n      expiresAt: toIsoDate(credit?.expires_at ?? credit?.expiresAt),\n    })),\n  };\n}\n\n// Consume one Codex rate-limit reset credit (irreversible, spends 1 credit)\nexport async function consumeCodexRateLimitResetCredit(accessToken, redeemRequestId, proxyOptions = null) {\n  if (!accessToken) {\n    throw new Error(\"No Codex access token available. Please re-authorize the connection.\");\n  }","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/open-sse/services/usage/codex.js#L148-L184","documentation":"After calling the Codex reset-credits endpoint, a non-OK response triggers this throw. The message prefers the API's own error text (message/error/detail fields) and falls back to a generic 'unavailable (status)' string. It means the backend refused or failed the reset-credits query.","triggerScenarios":"The reset-credits fetch returns non-2xx: 401/403 expired token, 404 endpoint moved, 429 rate limited, or 5xx ChatGPT backend outage; response body JSON parse failures also funnel into the generic fallback message.","commonSituations":"Expired Codex access token; ChatGPT backend API changed or is down; account not entitled to reset credits; proxy altering the response.","solutions":["If the message is generic (no API text), check response.status in logs — a 401/403 means re-authorize the Codex connection","Retry on 429/5xx after a backoff window","Verify the reset-credits endpoint URL in CODEX_CONFIG is still current","Confirm network/proxy path to the ChatGPT backend is clean"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if (!accessToken) throw new Error('Codex not authorized.');\n// optionally probe availability before consuming UI flows:\n// const ok = await fetchHealth(CODEX_CONFIG.resetCreditsUrl);","typeGuard":null,"tryCatchPattern":"try {\n  credits = await getCodexRateLimitResetCredits(accessToken, proxyOptions, data);\n} catch (e) {\n  const m = /\\((\\d{3})\\)\\.$/.exec(e.message); // generic fallback carries the status\n  const status = m ? Number(m[1]) : null;\n  if (status === 401 || status === 403) return reauthorizeCodex(conn);\n  if (status === 429 || (status && status >= 500)) { await backoff(); return retry(); }\n  throw e;\n}","preventionTips":["Prefer errors that include API-provided text — generic '(status)' messages mean the body did not parse; log raw responses","Refresh the Codex token before it expires to avoid most 401s","Back off on 429/5xx instead of hammering the endpoint","Track ChatGPT backend endpoint changes and update CODEX_CONFIG accordingly"],"tags":["network","http","codex","openai"],"backgroundTag":"http-error-response","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}