{"record":{"id":"4221f46bead69719","repo":"stablyai/orca","slug":"accountchanged","errorCode":"accountChanged","errorMessage":"The selected Codex account changed before reset.","messagePattern":"The selected Codex account changed before reset\\.","errorType":"exception","errorClass":"CodexResetCreditScopeRejection","httpStatus":null,"severity":"warning","filePath":"src/main/codex-accounts/service.ts","lineNumber":556,"sourceCode":"\n  private validateResetCreditScope(\n    expectedScope: CodexResetCreditExpectedScope,\n    requireCurrentOffer: boolean\n  ): { managedHomePath: string; rateLimits: RateLimitState } {\n    const rateLimitState = this.rateLimits.getState()\n    if (!sameRateLimitTarget(rateLimitState.codexTarget, expectedScope.target)) {\n      throw new CodexResetCreditScopeRejection(\n        'targetChanged',\n        rateLimitState,\n        'The active Codex rate-limit target changed before reset.'\n      )\n    }\n\n    const settings = this.store.getSettings()\n    if (\n      getSelectedCodexAccountIdForTarget(settings, expectedScope.target) !== expectedScope.accountId\n    ) {\n      throw new CodexResetCreditScopeRejection(\n        'accountChanged',\n        rateLimitState,\n        'The selected Codex account changed before reset.'\n      )\n    }\n    const account = settings.codexManagedAccounts.find(\n      (candidate) => candidate.id === expectedScope.accountId\n    )\n    if (!account || account.updatedAt !== expectedScope.accountRevision) {\n      throw new CodexResetCreditScopeRejection(\n        'accountRevisionChanged',\n        rateLimitState,\n        'The selected Codex account was updated before reset.'\n      )\n    }\n    const normalizedAccountTarget = normalizeCodexAccountSelectionTarget(\n      getCodexSelectionTargetForAccount(account)\n    )","sourceCodeStart":538,"sourceCodeEnd":574,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/codex-accounts/service.ts#L538-L574","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Re-select expectedScope.accountId for that target (setSelectedCodexAccountIdForTarget) and replay the idempotency key.","If the selection change is intended, discard this attempt and start a new one scoped to the now-selected account.","For fresh attempts, consume the rejectedBeforeProvider result and re-trigger from the current selection."],"exampleFix":"// before: account switched under a pending reset\nservice.consumeRateLimitResetCredit(key, scopeForAccountA) // rejects accountChanged\n\n// after: re-select the scope's account, then replay\nawait service.selectAccountForTarget(scope.accountId, scope.target)\nawait service.consumeRateLimitResetCredit(key, scope)","handlingStrategy":"validation","validationCode":"// Confirm the scope's account is still selected for this target.\nconst selected = getSelectedCodexAccountIdForTarget(store.getSettings(), scope.target)\nif (selected !== scope.accountId) {\n  // re-select or rebuild scope for the now-selected account before calling\n}","typeGuard":null,"tryCatchPattern":"try {\n  await service.consumeRateLimitResetCredit(key, scope)\n} catch (error) {\n  if (error instanceof CodexResetCreditScopeRejection && error.reason === 'accountChanged') {\n    // either re-select scope.accountId or rebuild scope for current selection\n  } else throw error\n}","preventionTips":["Disable account switching in the UI while a reset is in flight.","Rebuild expectedScope from the live selection right before consuming."],"tags":["codex-accounts","rate-limit-reset","scope-rejection","account-selection"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}