stablyai/orca · warning · CodexResetCreditScopeRejection

offerUnavailable

offerUnavailable

Error message

The Codex reset-credit offer is no longer available.

What it means

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.

Source

Thrown at src/main/codex-accounts/service.ts:591

      getCodexSelectionTargetForAccount(account)
    )
    if (!sameRateLimitTarget(normalizedAccountTarget, expectedScope.target)) {
      throw new CodexResetCreditScopeRejection(
        'accountRuntimeChanged',
        rateLimitState,
        'The selected Codex account belongs to a different runtime.'
      )
    }

    const currentScope = buildCodexResetCreditExpectedScope({
      target: rateLimitState.codexTarget,
      account: this.toSummary(account),
      limits: rateLimitState.codex
    })
    // Why: a same-key replay resolves an already-started provider mutation;
    // its credit snapshot may have refreshed, but its account/runtime identity may not change.
    if (requireCurrentOffer && !currentScope) {
      throw new CodexResetCreditScopeRejection(
        'offerUnavailable',
        rateLimitState,
        'The Codex reset-credit offer is no longer available.'
      )
    }
    if (
      requireCurrentOffer &&
      currentScope &&
      resetScopeKey(expectedScope) !== resetScopeKey(currentScope)
    ) {
      throw new CodexResetCreditScopeRejection(
        'offerChanged',
        rateLimitState,
        'The Codex reset-credit offer changed before reset.'
      )
    }

    return { managedHomePath: account.managedHomePath, rateLimits: rateLimitState }

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Refresh rate-limit state and only offer the reset action when buildCodexResetCreditExpectedScope returns a non-null scope.
  2. If the offer reappears, re-trigger a fresh attempt with a new idempotency key.
  3. Treat the rejectedBeforeProvider result as user-facing 'no reset available right now'.

Example fix

// before: firing a reset without checking an offer exists
service.consumeRateLimitResetCredit(uuid(), scope) // may reject offerUnavailable

// after: gate the UI on a live offer
const offer = buildCodexResetCreditExpectedScope({ target, account, limits: rateLimits.codex })
if (!offer) { show('No reset offer available'); return }
await service.consumeRateLimitResetCredit(crypto.randomUUID(), offer)
Defensive patterns

Strategy: validation

Validate before calling

// Only offer a reset when a live offer exists.
const limits = rateLimits.getState().codex
const offer = buildCodexResetCreditExpectedScope({ target, account, limits })
if (!offer) { show('No reset offer available'); return }
await service.consumeRateLimitResetCredit(crypto.randomUUID(), offer)

Type guard

const hasResetOffer = (scope: CodexResetCreditExpectedScope | null): scope is CodexResetCreditExpectedScope =>
  scope !== null

Try / catch

try {
  await service.consumeRateLimitResetCredit(key, scope)
} catch (error) {
  if (error instanceof CodexResetCreditScopeRejection && error.reason === 'offerUnavailable') {
    // no offer to consume; refresh and re-offer later
  } else throw error
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/1c28cfaa8432098f. Report an issue: GitHub.