{"record":{"id":"632fdb9ed6cc0e23","repo":"decolua/9router","slug":"failed-to-reset-codex-limit","errorCode":null,"errorMessage":"Failed to reset Codex limit","messagePattern":"Failed to reset Codex limit","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/app/(dashboard)/dashboard/usage/components/ProviderLimits/index.js","lineNumber":317,"sourceCode":"      await fetchQuota(connectionId, provider, { force: true });\n      setLastUpdated(new Date());\n    },\n    [fetchQuota],\n  );\n\n  const handleResetCodexLimit = useCallback(\n    async (connectionId, provider) => {\n      if (provider !== \"codex\" || resettingLimitId) return;\n\n      setResettingLimitId(connectionId);\n      setErrors((prev) => ({ ...prev, [connectionId]: null }));\n\n      try {\n        const response = await fetch(`/api/usage/${connectionId}/codex-reset-credits`, { method: \"POST\" });\n        const result = await response.json().catch(() => ({}));\n\n        if (!response.ok) {\n          throw new Error(result.message || result.error || result.code || \"Failed to reset Codex limit\");\n        }\n\n        await fetchQuota(connectionId, provider);\n        setLastUpdated(new Date());\n      } catch (error) {\n        setErrors((prev) => ({ ...prev, [connectionId]: error.message || \"Failed to reset Codex limit\" }));\n      } finally {\n        setResettingLimitId(null);\n      }\n    },\n    [fetchQuota, resettingLimitId],\n  );\n\n  const handleViewCodexResetCredits = useCallback(async (connection) => {\n    setResetCreditsState({ connection, loading: true, error: null, data: null });\n    try {\n      const response = await fetch(`/api/usage/${connection.id}/codex-reset-credits`, { cache: \"no-store\" });\n      const result = await response.json().catch(() => ({}));","sourceCodeStart":299,"sourceCodeEnd":335,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/app/(dashboard)/dashboard/usage/components/ProviderLimits/index.js#L299-L335","documentation":"handleResetCodexLimit POSTs to /api/usage/<connectionId>/codex-reset-credits to spend one of the connection's reset credits against the Codex rate-limit window. On non-OK responses it throws result.message || result.error || result.code || 'Failed to reset Codex limit'. Notable non-OK outcomes include 409 code:no_credit (no credits left), 400 (not a Codex/OAuth connection), 401 (credential refresh failed), and 5xx upstream errors.","triggerScenarios":"POST /api/usage/<id>/codex-reset-credits returns non-OK: 409 { code:'no_credit' } when no reset credits remain; 400 when the connection's provider is not codex or authType is neither oauth nor access_token; 401 'Credential refresh failed'; 502 when the upstream consume call returns an unexpected response.","commonSituations":"User clicks 'reset' after all credits were consumed (409 no_credit); connection re-authenticated as plain API key instead of OAuth; Codex OAuth refresh token expired; upstream OpenAI/Codex outage.","solutions":["If the message/code is no_credit (HTTP 409), wait for the credit to replenish or the rate-limit window to reset — there is nothing to redeem.","Confirm the connection is a Codex connection with authType oauth or access_token; plain API-key connections cannot redeem credits.","If you see 'Credential refresh failed', re-authorize the Codex connection to obtain a fresh refresh token.","Check upstream status / retry if the code is unknown_response (502), as the consume result was unparseable."],"exampleFix":"// before\nthrow new Error(result.message || result.error || result.code || \"Failed to reset Codex limit\");\n// after\nif (result.code === \"no_credit\") throw new Error(\"No Codex reset credits available — wait for replenishment\");\nthrow new Error(result.message || result.error || result.code || `Failed to reset Codex limit (HTTP ${response.status})`);","handlingStrategy":"validation","validationCode":"if (connection.provider !== \"codex\") throw new Error(\"Reset credits only apply to Codex connections\");\nif (![\"oauth\", \"access_token\"].includes(connection.authType)) throw new Error(\"Codex reset credits require an OAuth or access-token connection\");\nconst info = await fetch(`/api/usage/${connection.id}/codex-reset-credits`).then((r) => r.json()).catch(() => ({}));\nif (Array.isArray(info.credits) && info.credits.length === 0) throw new Error(\"No reset credits available\");","typeGuard":"const isConsumeResult = (r) => r && typeof r === \"object\" && typeof r.code === \"string\" && typeof r.reset === \"boolean\";","tryCatchPattern":"try {\n  const res = await fetch(`/api/usage/${connectionId}/codex-reset-credits`, { method: \"POST\" });\n  const result = await res.json().catch(() => ({}));\n  if (!res.ok) {\n    if (result.code === \"no_credit\") throw new Error(\"No Codex reset credits available\");\n    throw new Error(result.message || result.error || result.code || `Reset failed (HTTP ${res.status})`);\n  }\n} catch (error) {\n  setErrors((prev) => ({ ...prev, [connectionId]: error.message }));\n}","preventionTips":["Check available credits (GET) before consuming one (POST).","Keep the Codex connection on OAuth/access-token auth, not plain API keys.","Re-authorize promptly when credential refresh errors appear."],"tags":["quota","oauth","http-error"],"backgroundTag":"quota-exceeded","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}