actualbudget/actual · error

Unrecognized sync source: ${String(syncSource)}

Error message

Unrecognized sync source: ${String(syncSource)}

What it means

SelectLinkedAccountsModal normalizes its props in a useMemo switch over `syncSource`, which supports 'simpleFin', 'pluggyai', 'akahu', 'goCardless', and 'enableBanking'. Any other value falls to `default` and throws. This guards against the modal being opened with an unsupported bank-sync provider string.

Source

Thrown at packages/desktop-client/src/components/modals/SelectLinkedAccountsModal.tsx:243

            syncSource: 'akahu',
            externalAccounts: toSort as SyncServerAkahuAccount[],
            upgradingAccountId,
          };
        case 'goCardless':
          return {
            syncSource: 'goCardless',
            requisitionId: requisitionId!,
            externalAccounts: toSort as SyncServerGoCardlessAccount[],
            upgradingAccountId,
          };
        case 'enableBanking':
          return {
            syncSource: 'enableBanking',
            externalAccounts: toSort as SyncServerEnableBankingAccount[],
            upgradingAccountId,
          };
        default:
          throw new Error(`Unrecognized sync source: ${String(syncSource)}`);
      }
    }, [externalAccounts, syncSource, requisitionId, upgradingAccountId]);

  const { t } = useTranslation();
  const { isNarrowWidth } = useResponsive();
  const dispatch = useDispatch();
  const { data: allAccounts = [] } = useAccounts();
  const localAccounts = allAccounts.filter(a => a.closed === 0);
  const { initialDraftLinkAccounts, initiallyChosenAccounts } = useMemo(
    () =>
      computeInitialLinkState(
        localAccounts,
        propsWithSortedExternalAccounts.externalAccounts,
        upgradingAccountId,
      ),
    [
      localAccounts,
      propsWithSortedExternalAccounts.externalAccounts,

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Pass one of the supported values: 'simpleFin' | 'pluggyai' | 'akahu' | 'goCardless' | 'enableBanking'.
  2. Fix casing/typos — the check is exact ('simpleFin' with capital F, 'goCardless' with capital C).
  3. If a new provider was added to the backend, add its case to the useMemo switch and extend the props union.
  4. Validate syncSource at the call site before dispatching the modal.

Example fix

// before
<SelectLinkedAccountsModal
  syncSource={source.toLowerCase()}  // 'goCardless'.toLowerCase() => 'gocardless' => throws
// after
const SYNC_SOURCES = ['simpleFin', 'pluggyai', 'akahu', 'goCardless', 'enableBanking'] as const;
type SyncSource = typeof SYNC_SOURCES[number];
if (!SYNC_SOURCES.includes(source as SyncSource)) {
  throw new Error(`Unsupported sync source: ${source}`); // fail at call site
}
Defensive patterns

Strategy: validation

Validate before calling

const SYNC_SOURCES = ['simpleFin', 'pluggyai', 'akahu', 'goCardless', 'enableBanking'] as const;
type SyncSource = typeof SYNC_SOURCES[number];
if (!syncSource || !SYNC_SOURCES.includes(syncSource as SyncSource)) {
  console.error('Cannot open linked-accounts modal: bad syncSource', syncSource);
  return; // don't dispatch the modal
}

Type guard

type SyncSource = 'simpleFin' | 'pluggyai' | 'akahu' | 'goCardless' | 'enableBanking';
function isSyncSource(v: unknown): v is SyncSource {
  return typeof v === 'string' &&
    ['simpleFin', 'pluggyai', 'akahu', 'goCardless', 'enableBanking'].includes(v);
}

Try / catch

try {
  dispatch(pushModal({ name: 'select-linked-accounts', syncSource }));
} catch (err) {
  if (String(err).includes('Unrecognized sync source')) {
    dispatch(addNotification({ message: t('Unsupported bank provider') }));
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: Opening SelectLinkedAccountsModal with a `syncSource` prop that isn't one of the five supported providers — e.g. a typo ('simplefin' vs 'simpleFin'), a newly added provider not yet handled here, or undefined/null passed by a caller.

Common situations: Adding a new bank-sync backend (or regional provider) and wiring the modal before extending the switch; case-sensitive string mismatches in navigation code; callers passing the provider name in a different format than the union expects.

Related errors


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