actualbudget/actual · error · BankSyncError

TIMED_OUT

TIMED_OUT

Error message

TIMED_OUT

What it means

downloadSimpleFinTransactions wraps its HTTP post in a try/catch with a 60s timeout for single-account syncs and 300s for batch syncs (sync.ts:211-217). Any failure of that request — including the configured timeout firing — is logged and rethrown as BankSyncError('TIMED_OUT', 'TIMED_OUT'). It indicates the SimpleFin server did not respond in time, not necessarily that the bank itself failed.

Source

Thrown at packages/loot-core/src/server/accounts/sync.ts:216

  logger.log('Pulling transactions from SimpleFin');

  let res;
  try {
    res = await post(
      getServer().SIMPLEFIN_SERVER + '/transactions',
      {
        accountId: acctId,
        startDate: since,
      },
      {
        'X-ACTUAL-TOKEN': userToken,
      },
      // 5 minute timeout for batch sync, one minute for individual accounts
      Array.isArray(acctId) ? 300000 : 60000,
    );
  } catch (error) {
    logger.error('Suspected timeout during bank sync:', error);
    throw BankSyncError('TIMED_OUT', 'TIMED_OUT');
  }

  if (Object.keys(res).length === 0) {
    throw BankSyncError('NO_DATA', 'NO_DATA');
  }
  if (res.error_code) {
    throw BankSyncError(res.error_type, res.error_code);
  }

  let retVal = {};
  if (batchSync) {
    const batchErrors = res.errors;
    for (const accountId of Object.keys(res)) {
      if (accountId === 'errors') continue;

      const data = res[accountId];
      const error = batchErrors?.[accountId]?.[0];

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Retry the sync — timeouts are often transient; consider syncing accounts in smaller batches to stay under the 300s batch limit.
  2. Check connectivity from the sync server to the SimpleFin server URL (getServer().SIMPLEFIN_SERVER).
  3. Reduce the number of accounts in a batch sync so the request completes within the timeout.
  4. Verify the SimpleFin access URL/claims token is current; stale setup URLs cause slow failed lookups.
Defensive patterns

Strategy: retry

Validate before calling

// Keep batches small enough to finish within the 300s batch timeout:
if (Array.isArray(acctIds) && acctIds.length > 25) {
  throw new Error('Batch too large — split into smaller groups to avoid SimpleFin timeouts');
}

Type guard

function isTimedOutError(e: unknown): boolean {
  return typeof e === 'object' && e !== null &&
    (e as { errorType?: string }).errorType === 'TIMED_OUT' &&
    (e as { errorCode?: string }).errorCode === 'TIMED_OUT';
}

Try / catch

try {
  await syncAccount(accountId);
} catch (e) {
  if (isTimedOutError(e)) {
    await delay(5000);
    await syncAccount(accountId); // retry with backoff, smaller batch
  } else throw e;
}

Prevention

When it happens

Trigger: SimpleFin /transactions call exceeding the 60000ms (single account) or 300000ms (batch array) timeout, or the post throwing a network error; occurs inside syncAccount via downloadSimpleFinTransactions.

Common situations: Slow bank aggregation on SimpleFin's side; very large batch syncs of many accounts; network issues between sync server and SimpleFin; self-hosted setups with slow DNS/proxy.

Related errors


AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29). Data as JSON: /api/errors/b788ceeca520f934. Report an issue: GitHub.