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
- Pass one of the supported values: 'simpleFin' | 'pluggyai' | 'akahu' | 'goCardless' | 'enableBanking'.
- Fix casing/typos — the check is exact ('simpleFin' with capital F, 'goCardless' with capital C).
- If a new provider was added to the backend, add its case to the useMemo switch and extend the props union.
- 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
- Import and reuse the exported SyncSource union type at every call site instead of raw strings.
- Match casing exactly: 'simpleFin' and 'goCardless' are mixed-case.
- When adding a new bank-sync backend, update the union, the switch, and the type guard together.
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
- InitialFocus expects a single valid React element as its chi
- Account with ID ${upgradingId} not found.
- `payeeName` is required when adding a transaction
- Unrecognized menu option: ${String(name)}
- Unrecognized menu item: ${name}
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/7e43a64166b00f45.
Report an issue: GitHub.