{"record":{"id":"1c28cfaa8432098f","repo":"stablyai/orca","slug":"offerunavailable","errorCode":"offerUnavailable","errorMessage":"The Codex reset-credit offer is no longer available.","messagePattern":"The Codex reset-credit offer is no longer available\\.","errorType":"exception","errorClass":"CodexResetCreditScopeRejection","httpStatus":null,"severity":"warning","filePath":"src/main/codex-accounts/service.ts","lineNumber":591,"sourceCode":"      getCodexSelectionTargetForAccount(account)\n    )\n    if (!sameRateLimitTarget(normalizedAccountTarget, expectedScope.target)) {\n      throw new CodexResetCreditScopeRejection(\n        'accountRuntimeChanged',\n        rateLimitState,\n        'The selected Codex account belongs to a different runtime.'\n      )\n    }\n\n    const currentScope = buildCodexResetCreditExpectedScope({\n      target: rateLimitState.codexTarget,\n      account: this.toSummary(account),\n      limits: rateLimitState.codex\n    })\n    // Why: a same-key replay resolves an already-started provider mutation;\n    // its credit snapshot may have refreshed, but its account/runtime identity may not change.\n    if (requireCurrentOffer && !currentScope) {\n      throw new CodexResetCreditScopeRejection(\n        'offerUnavailable',\n        rateLimitState,\n        'The Codex reset-credit offer is no longer available.'\n      )\n    }\n    if (\n      requireCurrentOffer &&\n      currentScope &&\n      resetScopeKey(expectedScope) !== resetScopeKey(currentScope)\n    ) {\n      throw new CodexResetCreditScopeRejection(\n        'offerChanged',\n        rateLimitState,\n        'The Codex reset-credit offer changed before reset.'\n      )\n    }\n\n    return { managedHomePath: account.managedHomePath, rateLimits: rateLimitState }","sourceCodeStart":573,"sourceCodeEnd":609,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/codex-accounts/service.ts#L573-L609","documentation":"A CodexResetCreditScopeRejection with reason 'offerUnavailable'. validateResetCreditScope was called with requireCurrentOffer=true (fresh attempts only) and buildCodexResetCreditExpectedScope returned null for the current state — meaning no reset-credit offer is currently available for this account/target/limits combination. The reset is refused before reaching the provider because there is no valid offer to consume.","triggerScenarios":"Starting a FRESH reset attempt when the account/target is valid but the current rate-limit state carries no reset offer (e.g. quota already reset, offer window closed, or limits snapshot lacks a resettable offer). Replays (requireCurrentOffer=false) skip this check.","commonSituations":"User clicks 'reset' after the offer already lapsed; background rate-limit refresh removed the offer between the UI rendering the button and the click being processed; or the account has no eligible offer in the current limits.","solutions":["Refresh rate-limit state and only offer the reset action when buildCodexResetCreditExpectedScope returns a non-null scope.","If the offer reappears, re-trigger a fresh attempt with a new idempotency key.","Treat the rejectedBeforeProvider result as user-facing 'no reset available right now'."],"exampleFix":"// before: firing a reset without checking an offer exists\nservice.consumeRateLimitResetCredit(uuid(), scope) // may reject offerUnavailable\n\n// after: gate the UI on a live offer\nconst offer = buildCodexResetCreditExpectedScope({ target, account, limits: rateLimits.codex })\nif (!offer) { show('No reset offer available'); return }\nawait service.consumeRateLimitResetCredit(crypto.randomUUID(), offer)","handlingStrategy":"validation","validationCode":"// Only offer a reset when a live offer exists.\nconst limits = rateLimits.getState().codex\nconst offer = buildCodexResetCreditExpectedScope({ target, account, limits })\nif (!offer) { show('No reset offer available'); return }\nawait service.consumeRateLimitResetCredit(crypto.randomUUID(), offer)","typeGuard":"const hasResetOffer = (scope: CodexResetCreditExpectedScope | null): scope is CodexResetCreditExpectedScope =>\n  scope !== null","tryCatchPattern":"try {\n  await service.consumeRateLimitResetCredit(key, scope)\n} catch (error) {\n  if (error instanceof CodexResetCreditScopeRejection && error.reason === 'offerUnavailable') {\n    // no offer to consume; refresh and re-offer later\n  } else throw error\n}","preventionTips":["Gate the reset UI on a non-null buildCodexResetCreditExpectedScope.","Hide/disable the reset control while a rate-limit refresh is in flight."],"tags":["codex-accounts","rate-limit-reset","scope-rejection","offer"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}