From 1f2f8c5f10313acd074f8840b8938653134693ca Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 9 Mar 2026 20:50:29 +0000 Subject: [PATCH] [AI] Fix SimpleFIN batch sync error_code TypeError Fix "Cannot read properties of undefined (reading 'error_code')" that occurs during SimpleFIN batch sync by: 1. Adding null check for downloadSimpleFinTransactions result in simpleFinBatchSync (sync.ts) - the function can return undefined when user token is missing 2. Adding .catch() handler on individual processBankSyncDownload promises so a single account failure doesn't crash the entire batch via Promise.all rejection 3. Using optional chaining on syncResponse.res?.error_code in app.ts and handling the case where res is undefined with proper error reporting https://claude.ai/code/session_01XbHgxxrXYR3UTyW6VmYj47 --- packages/loot-core/src/server/accounts/app.ts | 13 ++++++++-- .../loot-core/src/server/accounts/sync.ts | 24 +++++++++++++++---- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/packages/loot-core/src/server/accounts/app.ts b/packages/loot-core/src/server/accounts/app.ts index 0b4587e92a..719ef0c9ef 100644 --- a/packages/loot-core/src/server/accounts/app.ts +++ b/packages/loot-core/src/server/accounts/app.ts @@ -1069,7 +1069,7 @@ async function simpleFinBatchSync({ const matchedTransactions: Array = []; const updatedAccounts: Array = []; - if (syncResponse.res.error_code) { + if (syncResponse.res?.error_code) { errors.push( handleSyncError( { @@ -1081,7 +1081,7 @@ async function simpleFinBatchSync({ account, ), ); - } else { + } else if (syncResponse.res) { const syncResponseData = await handleSyncResponse( syncResponse.res, account, @@ -1090,6 +1090,15 @@ async function simpleFinBatchSync({ newTransactions.push(...syncResponseData.newTransactions); matchedTransactions.push(...syncResponseData.matchedTransactions); updatedAccounts.push(...syncResponseData.updatedAccounts); + } else { + errors.push( + handleSyncError( + new Error( + 'Failed syncing account "' + account.name + '": empty response', + ), + account, + ), + ); } retVal.push({ diff --git a/packages/loot-core/src/server/accounts/sync.ts b/packages/loot-core/src/server/accounts/sync.ts index 6ec4bb9014..a1d7ef3362 100644 --- a/packages/loot-core/src/server/accounts/sync.ts +++ b/packages/loot-core/src/server/accounts/sync.ts @@ -1092,6 +1092,16 @@ export async function simpleFinBatchSync( startDates, ); + if (!res) { + return accounts.map(account => ({ + accountId: account.id, + res: { + error_type: 'NO_DATA', + error_code: 'NO_DATA', + }, + })); + } + const promises = []; for (let i = 0; i < accounts.length; i++) { const account = accounts[i]; @@ -1126,12 +1136,18 @@ export async function simpleFinBatchSync( } promises.push( - processBankSyncDownload(download, account.id, acctRow, newAccount).then( - res => ({ + processBankSyncDownload(download, account.id, acctRow, newAccount) + .then(res => ({ accountId: account.id, res, - }), - ), + })) + .catch(err => ({ + accountId: account.id, + res: { + error_type: err?.category || 'INTERNAL_ERROR', + error_code: err?.code || 'INTERNAL_ERROR', + }, + })), ); }