stablyai/orca · warning · CodexResetCreditScopeRejection

accountChanged

accountChanged

Error message

The selected Codex account changed before reset.

What it means

A CodexResetCreditScopeRejection with reason 'accountChanged'. The account currently selected for expectedScope.target (via getSelectedCodexAccountIdForTarget) no longer equals expectedScope.accountId. The reset credit is pinned to one account, so the provider call is refused rather than charging a different account's quota.

Source

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

  private validateResetCreditScope(
    expectedScope: CodexResetCreditExpectedScope,
    requireCurrentOffer: boolean
  ): { managedHomePath: string; rateLimits: RateLimitState } {
    const rateLimitState = this.rateLimits.getState()
    if (!sameRateLimitTarget(rateLimitState.codexTarget, expectedScope.target)) {
      throw new CodexResetCreditScopeRejection(
        'targetChanged',
        rateLimitState,
        'The active Codex rate-limit target changed before reset.'
      )
    }

    const settings = this.store.getSettings()
    if (
      getSelectedCodexAccountIdForTarget(settings, expectedScope.target) !== expectedScope.accountId
    ) {
      throw new CodexResetCreditScopeRejection(
        'accountChanged',
        rateLimitState,
        'The selected Codex account changed before reset.'
      )
    }
    const account = settings.codexManagedAccounts.find(
      (candidate) => candidate.id === expectedScope.accountId
    )
    if (!account || account.updatedAt !== expectedScope.accountRevision) {
      throw new CodexResetCreditScopeRejection(
        'accountRevisionChanged',
        rateLimitState,
        'The selected Codex account was updated before reset.'
      )
    }
    const normalizedAccountTarget = normalizeCodexAccountSelectionTarget(
      getCodexSelectionTargetForAccount(account)
    )

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Re-select expectedScope.accountId for that target (setSelectedCodexAccountIdForTarget) and replay the idempotency key.
  2. If the selection change is intended, discard this attempt and start a new one scoped to the now-selected account.
  3. For fresh attempts, consume the rejectedBeforeProvider result and re-trigger from the current selection.

Example fix

// before: account switched under a pending reset
service.consumeRateLimitResetCredit(key, scopeForAccountA) // rejects accountChanged

// after: re-select the scope's account, then replay
await service.selectAccountForTarget(scope.accountId, scope.target)
await service.consumeRateLimitResetCredit(key, scope)
Defensive patterns

Strategy: validation

Validate before calling

// Confirm the scope's account is still selected for this target.
const selected = getSelectedCodexAccountIdForTarget(store.getSettings(), scope.target)
if (selected !== scope.accountId) {
  // re-select or rebuild scope for the now-selected account before calling
}

Try / catch

try {
  await service.consumeRateLimitResetCredit(key, scope)
} catch (error) {
  if (error instanceof CodexResetCreditScopeRejection && error.reason === 'accountChanged') {
    // either re-select scope.accountId or rebuild scope for current selection
  } else throw error
}

Prevention

When it happens

Trigger: A reset is in flight or replayed, but the user (or a queued mutation) changed which managed Codex account is selected for that target — e.g. selectAccount/selectAccountForTarget ran between scope capture and validateResetCreditScope.

Common situations: User clicks the account switcher while a reset is pending; or a doSelectAccount mutation serialized ahead of the reset's validateResetCreditScope call. Also when a replayed durable attempt wakes up after selection drifted.

Related errors


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