actualbudget/actual · warning
RATE_LIMIT_EXCEEDED
RATE_LIMIT_EXCEEDED
Error message
RATE_LIMIT_EXCEEDED
What it means
Returned by getFailedSyncError for accounts with bank_sync_status 'rate-limit-exceeded'. The aggregator rejected the last sync because the institution or provider API request quota was hit. It is temporary — the descriptor signals the user to wait rather than retry immediately.
Source
Thrown at packages/desktop-client/src/accounts/syncStatus.ts:30
);
}
export function getFailedSyncError(
account: Pick<AccountEntity, 'bank_sync_status' | 'account_sync_source'>,
): { type: string; code: string } {
switch (account.bank_sync_status) {
case 'reauth-required':
if (account.account_sync_source === 'simpleFin') {
return { type: 'INVALID_ACCESS_TOKEN', code: 'INVALID_ACCESS_TOKEN' };
}
return { type: 'ITEM_ERROR', code: 'ITEM_LOGIN_REQUIRED' };
case 'attention-required':
return {
type: 'ACCOUNT_NEEDS_ATTENTION',
code: 'ACCOUNT_NEEDS_ATTENTION',
};
case 'rate-limit-exceeded':
return { type: 'RATE_LIMIT_EXCEEDED', code: 'RATE_LIMIT_EXCEEDED' };
case 'timed-out':
return { type: 'TIMED_OUT', code: 'TIMED_OUT' };
case 'account-missing':
return { type: 'ACCOUNT_MISSING', code: 'ACCOUNT_MISSING' };
default:
return { type: 'SYNC_ERROR', code: 'SYNC_ERROR' };
}
}
View on GitHub (pinned to d4334cb6e6)
Solutions
- Wait for the provider's rate-limit window to pass (typically 1-24 hours) before syncing again
- Reduce sync frequency / disable aggressive auto-sync schedules for the account
- Trigger a single manual sync instead of repeated retries
- If persistent, contact the provider (GoCardless/Plaid) about the institution's quota
Example fix
// before
await syncAccount(account.id); // keeps failing while rate-limited
// after
if (getFailedSyncError(account).code === 'RATE_LIMIT_EXCEEDED') {
scheduleRetry(hoursLater(24));
} Defensive patterns
Strategy: retry
Validate before calling
const err = getFailedSyncError(account);
if (err.code === 'RATE_LIMIT_EXCEEDED') {
// defer the sync call
} Type guard
function isRateLimited(v) {
return !!v && typeof v === 'object' && v.code === 'RATE_LIMIT_EXCEEDED';
} Prevention
- Throttle manual sync button usage per account
- Schedule syncs well below provider rate limits (e.g. at most every few hours)
- Back off exponentially instead of retrying immediately after a limit hit
When it happens
Trigger: Calling getFailedSyncError on an account whose bank_sync_status === 'rate-limit-exceeded' after a sync attempt was throttled by the provider/bank.
Common situations: Very frequent manual sync clicks; scheduled syncs above the institution's allowed rate; shared provider quotas exhausted during peak hours; multiple devices triggering sync simultaneously.
Related errors
- res.error_code
- response.reason || response.error_code
- response.reason || response.error || fallbackMessage
- Account with ID ${upgradingId} not found.
- Bank with ID ${bankId} not found.
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/f88b7e7cb18afa24.
Report an issue: GitHub.