actualbudget/actual · error · BankSyncError
NO_DATA
NO_DATA
Error message
NO_DATA
What it means
After a successful SimpleFin response, the code checks Object.keys(res).length === 0 and throws BankSyncError('NO_DATA', 'NO_DATA') (sync.ts:219-221). This means SimpleFin returned an empty object — no account data at all — even though the request itself completed. It typically indicates the account ids or date range matched nothing on the SimpleFin side.
Source
Thrown at packages/loot-core/src/server/accounts/sync.ts:220
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];
retVal[accountId] = {
transactions: data?.transactions?.all,
accountBalance: data?.balances,
startingBalance: data?.startingBalance,View on GitHub (pinned to d4334cb6e6)
Solutions
- Re-fetch the SimpleFin accounts list (GET on the SimpleFin access URL) and confirm the acctId still exists, then resync with the current id.
- Re-run the SimpleFin claims/setup flow to refresh the access URL if the account set changed.
- Remove any startDate restriction or widen the date range so data falls inside the window.
- Check the account on SimpleFin's dashboard for pending re-authentication of the underlying bank.
Defensive patterns
Strategy: fallback
Validate before calling
// Confirm the account exists in SimpleFin before syncing:
const accounts = await fetch(simplefinAccessUrl + '/accounts', {...}).then(r => r.json());
if (!accounts.accounts?.some(a => a.id === acctId)) {
throw new Error(`Account ${acctId} not present in SimpleFin — refresh the access URL`);
} Type guard
function isEmptyResponse(res: unknown): boolean {
return typeof res === 'object' && res !== null && Object.keys(res).length === 0;
} Try / catch
try {
await syncAccount(accountId);
} catch (e) {
if ((e as { errorCode?: string }).errorCode === 'NO_DATA') {
// re-fetch SimpleFin accounts / prompt bank re-auth, or skip gracefully
} else throw e;
} Prevention
- Periodically refresh the SimpleFin access/claims URL and re-list accounts.
- Handle NO_DATA as 'needs re-link or no data yet' rather than a hard failure in scheduled syncs.
- Skip gracefully on first syncs before the bank finishes aggregating.
- Warn users when a synced account disappears from the provider's account list.
When it happens
Trigger: The SimpleFin /transactions response body is an empty object, e.g. the requested acctId(s) are no longer in the SimpleFin account set or the startDate filter excludes everything.
Common situations: SimpleFin account was removed or renamed on the provider side; syncing with a malformed/stale account id; SimpleFin returned a 200 with no data after a bank re-auth was required; first-time sync before the bank finished aggregating.
Related errors
- INVALID_ACCESS_TOKEN
- TIMED_OUT
- response.reason || response.error_code
- response.reason || response.error || fallbackMessage
- results.reason || results.error_code
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/abe0c4fd72f6b870.
Report an issue: GitHub.